如果我打/ route2,我会在15s后得到响应,但是在这段时间内/ route1会立即给出响应。 服务器不应等待15秒,然后将响应发送到/ route1。
我读了https://medium.com/@cinish/nodejs-multiple-client-requests-694d6353218b,但听不懂。
我理解的是/ route2,是在控制台P1上,然后是setTimeout(),将其放入外部线程,然后将控制台P2然后是setTimeout(),将其放入外部线程。现在等待setTimeouts()到完成。
(此时,事件循环在等待p1和p2履行时必须处于繁忙状态,因此它不应接受任何新的客户端请求)。 但是确实如此。为什么?
app.get("/route1", (req, res) => {
res.send("Route1");
});
app.get("/route2", async (req, res) => {
const p1 = new Promise((resolve, reject) => {
console.log("P1");
setTimeout(() => {
console.log(5);
resolve();
}, 15000);
})
const p2 = new Promise((resolve, reject) => {
console.log("P2")
setTimeout(() => {
console.log(1);
resolve();
}, 1000);
});
const ans = await Promise.all([p1, p2]);
res.send("Route2");
})
答案 0 :(得分:1)
setTimeout()
是“非阻止”。这意味着它将设置计时器,立即从setTimeout()
返回,然后继续执行其余代码。
因此,在您的情况下,/route2
创建了两个承诺,设置了两个计时器,然后等待Promise.all()
完成。在到达await
的那一刻,您的async
路由处理程序将返回一个promise,并将控制权返回到事件循环。
因此,/route1
请求一到,就可以对其进行处理。 /route2
在两个计时器都完成后才处于活动状态。
然后,当准备启动更长的计时器时,下一次JS解释器返回事件循环以检查其他事情时,它将看到计时器,正在处理计时器回调并且计时器回调将解决p1
承诺,然后使Promise.all()
得到解决。
如果我打/ route2,我会在15s后得到响应,但是在这段时间内/ route1会立即给出响应。服务器不应等待15秒,然后将响应发送给/ route1。
如关于setTimeout()
的说明是非阻塞的,因此在/route2
处理程序等待两个计时器触发时,nodejs可以自由处理其他事件(例如传入的/route1
事件)。
我理解的是/ route2,是在控制台P1上,然后是setTimeout(),将其放入外部线程,然后将控制台P2然后是setTimeout(),将其放入外部线程。现在等待setTimeouts()到完成。
计时器不在外部线程中运行。它们是nodejs事件循环中的某种独特设计。计时器按到期时间的顺序存储在排序的链表中。每次JS解释器返回事件循环并到达事件循环的计时器部分时,它仅检查链接列表中最前面的计时器,以查看其时间是否到了。如果是这样,它将触发该事件。如果没有,它将继续寻找其他类型的事件。
最终,如果事件循环不执行任何操作而进入睡眠状态,它将在适当的时间睡眠,以便在计划的下一个计时器运行之前及时唤醒(如果在此之前没有其他唤醒方式)。
(此时,事件循环在等待p1和p2填充时必须处于繁忙状态,因此它不应接受任何新的客户端请求)。但这是为什么?
这是您的主要错误假设。此时,事件循环完全可以自由处理其他事件。设置了这两个计时器,事件循环将在其时间到期时运行其回调,但是在此之前,事件循环将处理任何其他传入事件,例如/route1
请求。