0

All:

I am pretty new to Node async programming, I wonder how can I write some Express request handler which can handle time consuming heavy calculation task without block Express handling following request?

I thought setTimeout can do that to put the job in a event loop, but it still block other requests:

var express = require('express');
var router = express.Router();


function heavy(callback){
    setTimeout(callback, 1);
}

router.get('/', function(req, res, next) {
    var callback = function(req, res){
        var loop = +req.query.loop;
        for(var i=0; i<loop; i++){
            for(var j=0; j<loop; j++){}
        }
        res.send("finished task: "+Date.now());
    }.bind(null, req, res);

    heavy(callback)
}); 

I guess I did not understand how setTimeout works(my understanding about setTimeout is after that 1ms delay it will fire up the callback in a seperated thread/process without blocking other call of heavy), could any one show me how to do this without blocking other request to heavy()?

Thanks

Kuan
  • 11,149
  • 23
  • 93
  • 201

1 Answers1

2

Instead of setTimeout it's better to use process.nextTick or setImmediate (depending od when you want your callback to be run). But it is not enough to put a long running code into a function because it will still block your thread, just a millisecond later.

You need to break your code and run setImmediate or process.nextTick multiple times - like in every iteration and then schedule a new iteration from that. Otherwise you will not gain anything.

Example

Instead of a code like this:

var a = 0, b = 10000000;

function numbers() {
  while (a < b) {
    console.log("Number " + a++);
  }
}

numbers();

you can use code like this:

var a = 0, b = 10000000;

function numbers() {
  var i = 0;
  while (a < b && i++ < 100) {
    console.log("Number " + a++);
  }
  if (a < b) setImmediate(numbers);
}

numbers();

The first one will block your thread (and likely overflow your call stack) and the second one will not block (or, more precisely, it will block your thread 10000000 times for a very brief moment, letting other stuff to run in between those moments).

You can also consider spawning an external process or writing a native add on in C/C++ where you can use threads.

For more info see:

Community
  • 1
  • 1
rsp
  • 107,747
  • 29
  • 201
  • 177
  • Thanks, could you tell me why in my case, the next request still get blocked event I use setTimeout? I thought setTimeout will choose a differernt thread to run that heavy() and leave the Express request handler thread free. But it seems the new request just can not come in... – Kuan Apr 03 '17 at 19:01
  • @Kuan setTimeout runs in the same thread. It makes the code run later but still it will block the main thread and the event loop for the time that the setTimeout callback runs. You need to make multiple setTimeouts (or process.nextTick or setImmediate callbacks) to give the event loop a chance to be processed in between those callbacks as I already explained it in my answer. – rsp Apr 04 '17 at 09:19