Ryan Dahl has said he invented NodeJS to solve the file upload progress bar problem (https://youtu.be/SAc0vQCC6UQ). Using technology available in 2009 when Node was introduced, so before Express and more advanced client-side javascript libraries that automagically tell you progress updates, how exactly did NodeJS solve this problem?
Trying to use just Core NodeJS now, I understand with the request stream I can look at the header, get the total file size, and then get the size of each chunk of data as it comes through, to tell me the percent complete. But then I don't understand how to stream those progress updates back to the browser, since the browser doesn't seem to update until request.end().
Once again I want to wrap my ahead around how NodeJS originally solved this progress update problem. WebSockets weren't around yet, so you couldn't just open a WebSocket connection to the client and stream the progress updates back to the browser. Was there another client-side javascript technology that was used?
Here is my attempt so far. Progress updates are streamed to the server-side console, but the browser only updates once the response stream receives response.end().
var http = require('http');
var fs = require('fs');
var server = http.createServer(function(request, response){
response.writeHead(200);
if(request.method === 'GET'){
fs.createReadStream('filechooser.html').pipe(response);
}
else if(request.method === 'POST'){
var outputFile = fs.createWriteStream('output');
var total = request.headers['content-length'];
var progress = 0;
request.on('data', function(chunk){
progress += chunk.length;
var perc = parseInt((progress/total)*100);
console.log('percent complete: '+perc+'%\n');
response.write('percent complete: '+perc+'%\n');
});
request.pipe(outputFile);
request.on('end', function(){
response.end('\nArchived File\n\n');
});
}
});
server.listen(8080, function(){
console.log('Server is listening on 8080');
});
filechooser.html:
<!DOCTYPE html>
<html>
<body>
<form id="uploadForm" enctype="multipart/form-data" action="/" method="post">
<input type="file" id="upload" name="upload" />
<input type="submit" value="Submit">
</form>
</body>
</html>
Here is an Updated attempt. The browser now displays progress updates, but I'm pretty sure this isn't the actual solution Ryan Dahl originally came up with for a production scenario. Did he use long polling? What would that solution look like?
var http = require('http');
var fs = require('fs');
var server = http.createServer(function(request, response){
response.setHeader('Content-Type', 'text/html; charset=UTF-8');
response.writeHead(200);
if(request.method === 'GET'){
fs.createReadStream('filechooser.html').pipe(response);
}
else if(request.method === 'POST'){
var outputFile = fs.createWriteStream('UPLOADED_FILE');
var total = request.headers['content-length'];
var progress = 0;
response.write('STARTING UPLOAD');
console.log('\nSTARTING UPLOAD\n');
request.on('data', function(chunk){
fakeNetworkLatency(function() {
outputFile.write(chunk);
progress += chunk.length;
var perc = parseInt((progress/total)*100);
console.log('percent complete: '+perc+'%\n');
response.write('<p>percent complete: '+perc+'%');
});
});
request.on('end', function(){
fakeNetworkLatency(function() {
outputFile.end();
response.end('<p>FILE UPLOADED!');
console.log('FILE UPLOADED\n');
});
});
}
});
server.listen(8080, function(){
console.log('Server is listening on 8080');
});
var delay = 100; //delay of 100 ms per chunk
var count =0;
var fakeNetworkLatency = function(callback){
setTimeout(function() {
callback();
}, delay*count++);
};