Answer the question
In order to leave comments, you need to log in
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.
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);
// 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
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
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 questionAsk a Question
731 491 924 answers to any question