javascript 在 Node.js 中,setTimeout() 会阻塞事件循环吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8950978/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 05:07:31  来源:igfitidea点击:

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

javascriptnode.js

提问by TIMEX

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

如果我有一个简单的 setTimeout() 函数,并将其设置为 10 秒...

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

整个服务器在这 10 秒内就死了???这是真的?那是我听到的。

回答by Jamund Ferguson

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 setTimeoutblocking the event loop it was a whileloop that deliberatelyblocks 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 setTimeoutwill work great.

答案是否定的。你的链接Node.js:你将如何重新创建“setTimeout”函数而不阻塞事件循环?表明不是setTimeout闭塞事件循环,这是一个while循环,它故意块事件循环。如果您希望您的服务器速度更快,您不想阻止事件循环。诸如此类的异步回调setTimeout会很好用。

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

您是否出于某种原因试图阻止(例如测试或其他什么?)

回答by Jerry Tian

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.

另一个发现可能会帮助正在学习 Node.js 并对这个问题感到好奇的其他人,但被现代浏览器的隐藏行为所欺骗。

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

代码真的很简单,我只是想测试一下我对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!

如果我启动三个浏览器窗口(更准确地说是 Firefox),同时打开这个路由定义的 URL,并从 Node.js 中查看控制台日志,很明显请求不是并发处理的

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.

而且,奇怪的是,它也没有以串行模式运行(如果 Node.js 被 setTimeout 阻止,它应该)。第一个和第二个请求之间的间隔是 20 秒,但第二个和第三个请求之间只有 2 秒。

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.

所以,我很快设置了另一个测试,但这次是通过发出多个 curl 命令来代替。

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)

回答by JaredPar

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

那不是真的。当您调用setTimeout并返回代码时,服务器不会被阻止。setTimeout在等待您的特定计时器触发时可以自由地处理其他事件(可能是其他回调)

回答by Ken Wayne VanderLinde

The link which you seem to be confused about does notstate that setTimeoutwill block. Rather, the OP in that question was trying to make a custom function called waitthat would behave like setTimeout. The waitfunction is the blocking function - setTimeoutwill not block.

您似乎感到困惑的链接并未说明setTimeout会阻止。相反,该问题中的 OP 试图创建一个调用的自定义函数wait,其行为类似于setTimeout. 该wait函数是阻塞函数——setTimeout不会阻塞。

回答by pirs

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

主进程似乎被主机单线程处理并被 asetTimeout或 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://www.journaldev.com/7462/node-js-architecture-single-threaded-event-loop

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

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