在NodeJS中忙着等待



有两个异步函数。一个将设置一个变量,另一个将等待vaible更改,如下所示的代码。尽管通常的做法是事件或承诺,在我的情况下是不可行的。

function delay(ms: number): Promise<void> {
return new Promise(resolve => {
setTimeout(() => { resolve(); }, ms);
});
}
function async fn1() {
let done = false;
(async () => {
await delay(100); // simulate some work
done = true;
})();
await (async () => {
while (!done) { }
// do other things
})();
}
function async fn2() {
let done = false;
(async () => {
await delay(100); // simulate some work
done = true;
})();
await (async () => {
while (!done) {
await delay(200); // introduce some extra delay
}
// do other things
})();
}

我想知道为什么fn1会卡在while循环中,而fn2会工作。因为他们之间唯一的区别是后者引入了一些额外的等待。这与某些潜在因素有关吗NodeJS/V8解释器的线程调度机制?

我使用的是Node 12.18.3和TypeScript 4.0.3。

EDIT:修复fn2的定义。

Javascript是单线程的。因此,任何形式的繁忙等待都会导致线程完全阻塞,从而阻止它进入事件循环,这意味着不会处理任何事件。

在C级,解释器非常简单。由于它是单线程的,所以不需要任何复杂的逻辑,只需要一个无限while循环。在伪代码中,它是这样的:

do {
event_queue = execute_javascript()
completed_events = wait_for_events()
for_each (event from completed_events) {
this_event = event_queue.find_one_matching(event)
execute_javascript(this_event.callback)
}
} while (there_is_pending_events)

正如您所看到的,解释器中没有任何东西是并行运行的。它们都按顺序运行。异步代码并行等待,但不并行执行。

在您的代码中,while(){}循环卡在execute_javascript()中,直到while循环完成才会返回。这意味着口译员被卡住了。

while(){}循环中添加await会导致execute_javascript()在等待时返回(并将在await之后的行中再次继续(,从而允许解释器继续等待wait_for_events()处的事件。

注意:有些人会告诉你javascript使用后台线程来处理异步代码。他们错了。Node.js(不是浏览器(确实使用一个、单个、额外的线程来处理磁盘I/O,但只处理磁盘I/O。网络I/O是在如上所述的主线程中完成的。磁盘I/O是这样做的,因为Windows、Linux和BSD(BSD包括Mac OSX(之间对异步磁盘I/O API的兼容性非常小

如果您对javascript中事件循环和异步代码执行的低级别解释感兴趣,您可能会对我对这些其他相关问题的回答感兴趣。在某些方面,我解释了硬件如何处理它。在一些方面,我探索了它是如何在C/C++中完成的:

我对异步操作的理解正确吗?

有没有其他方法来实现";"倾听";函数没有无穷while循环?

node js-回调执行期间传入事件会发生什么

我知道回调函数是异步运行的,但为什么呢?

对于第一个函数fn1,您将async放在函数之前,但对于fn2,您没有。试着从第一个函数中删除它,看看它是否仍然卡住。

最新更新