NodeJS code executes differently when run via browser and when run via curl in terminal

profile for Nikola at Stack Overflow, Q&A for professional and enthusiast programmers
I’m a big fan of Stack Overflow and I tend to contribute regularly (am currently in the top 0.X%). In this category (stackoverflow) of posts I will will be posting my top rated questions and answers. This, btw, is allowed as explained in the meta thread here.

My quesiton was:

I have the following simple NodeJS code:

var http = require("http");

http.createServer(function(request, response){
    response.writeHead(200);
    setTimeout(function(){
        response.write("This printed 3 secs later, ait?");
        response.end();},3000);

    response.write("This will be printed before.\n");}).listen(8080);

If I run the script with node scriptname.js and then access it via curl in terminal like this:

curl http://localhost:8080

I get an output as expected, first it prints This will be printed before., then after 3 seconds it prints This printed 3 secs later, ait?.

However, when I open http://localhost:8080 in my browser (newest versions of Chrome, Firefox) page loads for 3 seconds and it prints the text This will be printed before. This printed 3 secs later, ait? all at once. Why does this happen and how could I make the same behavior in the browser?

edit: So, as Ken stated in his answer

…this is simply due to the behavior of the browser rendering engine to render the contents. The rendering engine cashes the contents until response.end();

and advised to go and check out Socket.IO, I came up with this working example which uses expressand Socket.IO:

//timeoutTest.js
var express = require('express'),
    app = express(),
    server = require('http').createServer(app),
    io = require('socket.io').listen(server);

server.listen(8080);

app.use(express.static(__dirname +'/'));

app.get('/',function(req, res){
   res.sendfile(__dirname +'/timeoutTest.html');});

io.sockets.on('connection',function(client){
   client.emit('msg',"This prints right now on connection.");

   setTimeout(function(){
      client.emit('msg',"This prints out after 3 secs.");},3000);});
//timeoutTest.html
<!DOCTYPE html><html><head><script src="/socket.io/socket.io.js"></script><script src="jquery.js"></script><script>
    $(document).ready(function(){var server = io.connect('http://localhost');
        server.on('msg',function(data){
            $('body').append(data +"<br/>");});});</script></head><body></body></html>

 

The answer, by Ken OKABE, was:

I think this is simply due to the behavior of the browser rendering engine to render the contents. The rendering engine cashes the contents until response.end(); arrives, then renders whole.

Basically, HTML contents in the browser are never updated automatically by incremental server pushsuch as response.write. You must pull data from the server to the browser client by Ajax and DHTML/js technique. curl in terminal is completely different story in terms of the mere output of the node server.

If you seek more interactive behavior between node server and browser client, if you want server push feature, websocket is the way to go, and also investigate node stream stuff. Socket.IO is famous, and for node stream https://github.com/substack/stream-handbook should be interesting to you.

I personally do this on my own project: http://kenokabe.github.io/MarkdownLive/. I write stuff using Markdown and needed a streaming preview, so I created by myself. The preview screen is a Browser HTML page, and the HTML contents rendered and updated incrementally in streaming manner.

Written by Nikola Brežnjak