Question

Noob question on using callbacks as a control flow pattern with Node and the http class. Based on my understanding of the event loop, all code is blocking, i/o is non-blocking and using callbacks, here's the a simple http server and a pseudo rest function:

// Require
var http = require("http"); 

// Class 
function REST() {};

// Methods
REST.prototype.resolve = function(request,response,callback) {

    // Pseudo rest function
    function callREST(request, callback) {

        if (request.url == '/test/slow') {
            setTimeout(function(){callback('time is 30 seconds')},30000);
        } else if (request.url == '/test/foo') {
            callback('bar');
        }
    }

    // Call pseudo rest
    callREST(request, callback);

}

// Class
function HTTPServer() {};

// Methods
HTTPServer.prototype.start = function() {

    http.createServer(function (request, response) {

        // Listeners
        request.resume();
        request.on("end", function () {

            // Execute only in not a favicon request
            var faviconCheck = request.url.indexOf("favicon");
            if (faviconCheck < 0) { 

                //Print
                console.log('incoming validated HTTP request: ' + request.url);

                //Instantiate and execute on new REST object
                var rest = new REST();
                rest.resolve(request,response,function(responseMsg) {
                    var contentType = {'Content-Type': 'text/plain'};
                    response.writeHead(200, contentType); // Write response header
                    response.end(responseMsg); // Send response and end
                    console.log(request.url + ' response sent and ended');
                });
            } else {
                response.end();
            }
        });
    }).listen(8080);

    // Print to console
    console.log('HTTPServer running on 8080. PID is ' + process.pid);
} 

// Process
// Create http server instance
var httpServer = new HTTPServer();

// Start
httpServer.start();

If I open up a browser and hit the server with "/test/slow" in one tab then "/test/foo" in another, I get the following behavior - "foo" responds with "Bar" immediately and then 30 secs late, "slow" responds with "time is 30 seconds". This is what I was expecting.

But if I open up 3 tabs in a browser and hit the server with "/test/slow" successively in each tab, "slow" is being processed and responds serially/synchronously so that the 3 responses appear at 30 second intervals. I was expecting the responses right after each other if they were being processed asynchronously.

What am I doing wrong?

Thank you for your thoughts.

Was it helpful?

Solution

This is actually not the server's fault. Your browser is opening a single connection and re-using it between the requests, but one request can't begin until the previous finishes. You can see this a couple of ways:

  • Look in the network tab of the Chrome dev tools - the entry for the longest one will show the request in the blocking state until the first two finish.
  • Try opening the slow page in different browsers (or one each in normal and incognito windows) - this prevents sharing connections.

Thus, this will only happen if the same browser window is making multiple requests to the same server. Also, note that XHR (AJAX) requests will open separate connections so they can be performed in parallel. In the real world, this won't be a problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top