L
L
Ler Den2021-11-02 21:22:21
JavaScript
Ler Den, 2021-11-02 21:22:21

Why is the 'data' event fired only after the data is fully loaded?

Hello.
The task is to ensure that when data is loaded on the server, some trigger fires, which would register how much data was received per unit of time. Those. the client sends binary data via POST. As soon as the data (even if partially) reaches the server, it counts how many bytes have arrived and notifies another client about it (for example, via websockets).

How to make sure that information about the receipt of data on the server appears in real time (or as close to it as possible)? Web sockets are not suitable for sending data, only http.

Made as follows. There is a simple POST data sending to the NodeJS server. I want to start getting data on the server as soon as it gets there, as soon as possible without waiting for the entire request body.

For this I use the 'data' event.
https://nodejs.org/uk/docs/guides/anatomy-of-an-ht...
https://nodejs.org/api/stream.html#event-data

Expect that once the request reaches the server, the data will immediately appear in the 'data' event.
The problem is that the 'data' event is triggered with a delay, and the larger the size of the sent data, the greater the delay. For example, if I send 1Mb, then the delay is almost invisible, but if I send 50Mb, then the delay becomes very significant (about 10 seconds). We are talking about a real server, because on the localhost it is not so noticeable.

It seems that the 'data' event is triggered only after the data has completely arrived at the server.
I can't figure out why this is happening? Below is a simple example that clearly shows that the data in 'data' on the server appears with a delay.

Server side code.

spoiler
const http = require('http');

var firstByte = null;
var serverLog = {};
var server = http.createServer((request, response) => {
    const { headers, method, url } = request;
    let body = [];
    request.on('error', (err) => {
    }).on('data', (chunk) => {
        if (!firstByte) {
            firstByte = Date.now();
            serverLog.backendReceivedFirstData = firstByte;
        }
    }).on('end', () => {
        var end = Date.now();
        serverLog.backendReceivedAllData = end;

        if (url === '/') {
            response.statusCode = 200;
            response.setHeader('Content-Type', 'text/html');
            response.write('<h1>Hello World</h1>');
        } else {
            response.statusCode = 200;
            response.setHeader('Content-Type', 'application/json');
            response.write(JSON.stringify(serverLog));
        }

        firstByte = null;
        serverLog = {};
        response.end();
    });
    var requestReceived = Date.now();
    serverLog.backendRequestReceived = requestReceived;
});

server.listen(4000);


Browser part code:
spoiler
// send 50Mb
            var dataToSend = prepareDataBlob(50 * 1024 * 1024);
            var start = Date.now();

            fetch("http://localhost:4000/upload?a=" + Date.now(), {
                body: dataToSend,
                method: "post"
            }).then(async response => {
                const data = await response.json();
                console.log(`difference between start and server received a request: ${data.backendRequestReceived - start}`);
                console.log(`difference between start and first byte received on server: ${data.backendReceivedFirstData - start}`);
                console.log(`difference between start and all data received on server: ${data.backendReceivedAllData - start}`);
            });

function prepareDataBlob(fileSize) {
            const DEFAULT_UPLOAD_DATA = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
            var data = '';
            var count = fileSize / DEFAULT_UPLOAD_DATA.length;
            for (var j = 0; j < count; j++) data += DEFAULT_UPLOAD_DATA;
            var dataBlob = new Blob([data], {
                type: 'application/octet-stream'
            });
            return data;
        }

Answer the question

In order to leave comments, you need to log in

1 answer(s)
L
Lynn "Coffee Man", 2021-11-03
@givemoneybiatch

Are you sure you don't have any proxying? Or maybe it's the browser somehow manages to be weird.
I checked on such a script

const http = require('http');

const server = http.createServer((request, response) => {
    let size = 0;
    let n = 0;
    request.on('error', (err) => {
    }).on('data', (chunk) => {
        size += chunk.length;
        n++;
        console.log('chunk', n, size);
    }).on('end', () => {
        console.log('end', size);
        response.statusCode = 200;
        response.setHeader('Content-Type', 'text/plain');
        response.end('done\n');
    });
});

server.listen(4000);

$ truncate --size 1000000 data
$ curl localhost:4000 --data-binary @data

and I see this output:
chunk 1 32768
chunk 2 98304
chunk 3 163840
chunk 4 229376
chunk 5 294912
chunk 6 360448
chunk 7 425984
chunk 8 491520
chunk 9 557056
chunk 10 622592
chunk 11 688128
chunk 12 753664
chunk 13 819200
chunk 14 884736
chunk 15 950272
chunk 16 1000000
end 1000000

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question