In Node.js, does setTimeout() block the event loop?

If I have a simple setTimeout() function, and set it for 10 seconds…

The the entire server is dead inside those 10 seconds??? Is this true? That’s what I heard.

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

The answer is no. What your link Node.js: How would you recreate the 'setTimeout' function without it blocking the event loop? showed was not a setTimeout blocking the event loop it was a while loop that deliberately blocks the event loop. If you want your server to be fast you do not want to block the event loop. An asynchronous callback such as setTimeout will work great.

Are you trying to block for some reason (like testing or something?)

Solution 2

Another finding that may help others who are learning Node.js and curious of this question, but tricked by a hidden behavior of modern browsers.

The code is really simple, I just want to test my understanding of the “async nature” of Node.js.

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

router.get('/', function(req, res, next) {
    console.log("route begin");
    var start = new Date();


    setTimeout(function() {
        res.render('index', { title: start + ' - ' + new Date()});
    }, 20000);//force delay of 20 seconds.

    console.log("route end");
});

module.exports = router;

If I start three browser windows(Firefox, more accurately), open the URL defined by this route at the same time, and check the console log from Node.js, it is clear the request is not handled concurrently!

I tried the test several times, the results are same.

The typical log output is like this:

route begin at: Fri Aug 28 2015 18:35:57 GMT+0800 (CST)
route end at: Fri Aug 28 2015 18:35:57 GMT+0800 (CST)
route begin at: Fri Aug 28 2015 18:36:18 GMT+0800 (CST)
route end at: Fri Aug 28 2015 18:36:18 GMT+0800 (CST)
route begin at: Fri Aug 28 2015 18:36:20 GMT+0800 (CST)
route end at: Fri Aug 28 2015 18:36:20 GMT+0800 (CST)

And also, strangely, it was not running in serial mode either(if Node.js is blocked by setTimeout, it should). The interval between the first and second request is 20 seconds, but the second and the third is just 2 seconds.

After scratching my head for quite a while, I suddenly recall that the browser has a connection limit on the same host!

So, I quickly setup another test, but this time by issuing multiple curl commands instead.

Hallelujah!

route begin at: Fri Aug 28 2015 18:42:51 GMT+0800 (CST)
route end at: Fri Aug 28 2015 18:42:51 GMT+0800 (CST)
route begin at: Fri Aug 28 2015 18:42:53 GMT+0800 (CST)
route end at: Fri Aug 28 2015 18:42:53 GMT+0800 (CST)
route begin at: Fri Aug 28 2015 18:42:55 GMT+0800 (CST)
route end at: Fri Aug 28 2015 18:42:55 GMT+0800 (CST)

Solution 3

The link which you seem to be confused about does not state that setTimeout will block. Rather, the OP in that question was trying to make a custom function called wait that would behave like setTimeout. The wait function is the blocking function – setTimeout will not block.

Solution 4

That is not true. When you call setTimeout and return out of your code the server is not blocked. It is free to process other events (possibly other setTimeout callbacks) while waiting for your particular timer to fire

Solution 5

The main process seems to be monothreaded by host and blocked by a setTimeout or a while.

However, there is an alternative with this code which works as expected and don’t block the main process or the event loop:

var express = require('express')
var app = express()

function setTimeoutAsync (callback, time) {
  setTimeout(function () {
    callback()
  }, time)
  return 0
}

app.get('/', function (req, res, next) {
    console.log("route begin")
    var start = +new Date()
    setTimeoutAsync(function () {
      console.log("route done")
      res.json({ delay: ((+new Date()) - start) + 'ms' })
    }, 5000)
    console.log("route end")
});

app.listen(8000) 

In terminal :

route begin // first page
route end
route begin // second page
route end
route begin // third page
route end
route done // first render
route done // second render
route done // third render

Good sources:

https://www.journaldev.com/7462/node-js-architecture-single-threaded-event-loop

https://nodejs.org/en/docs/guides/blocking-vs-non-blocking/

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply