这真的很简单。在内部,node.js 由这种类型的循环组成:
- 从事件队列中获取一些东西
- 运行任何指示的任务并运行它直到它返回
- 当上述任务完成后,从事件队列中获取下一项
- 运行任何指示的任务并运行它直到它返回
- 冲洗、起泡、重复——一遍又一遍
如果在某个时刻,事件队列中没有任何内容,则进入睡眠状态,直到将某些内容放入事件队列中。
因此,如果一段 Javascript 处于while()
循环中,则该任务未完成,并且按照上述顺序,在该先前任务完全完成之前,不会从事件队列中挑选任何新内容。因此,一个很长或永远运行的while()
循环只会使工作变得困难。因为 Javascript 一次只运行一项任务(单线程用于 JS 执行),如果该任务在 while 循环中旋转,则其他任何任务都无法执行。
这是一个可能有助于解释它的简单示例:
var done = false;
// set a timer for 1 second from now to set done to true
setTimeout(function() {
done = true;
}, 1000);
// spin wait for the done value to change
while (!done) { /* do nothing */}
console.log("finally, the done value changed!");
有些人可能会合乎逻辑地认为 while 循环将旋转直到计时器触发,然后计时器将更改done
to的值,true
然后 while 循环将完成,console.log()
最后将执行。那不是会发生的事情。这实际上将是一个无限循环,并且console.log()
永远不会执行该语句。
问题是,一旦您进入while()
循环中的自旋等待,就无法执行其他 Javascript。因此,想要更改变量值的计时器done
无法执行。因此,while 循环条件永远不会改变,因此它是一个无限循环。
以下是 JS 引擎内部发生的事情:
done
变量初始化为 false
setTimeout()
从现在起 1 秒内安排一个计时器事件
- while 循环开始旋转
- 进入 while 循环旋转 1 秒后,计时器在内部触发 JS 引擎,并将计时器回调添加到事件队列中。这可能发生在 JS 引擎内部的不同线程上。
- while 循环一直在旋转,因为
done
变量永远不会改变。因为它继续旋转,JS 引擎永远不会完成这个执行线程,也永远不会从事件队列中提取下一个项目。
node.js 是一个事件驱动的环境。为了在现实世界的应用程序中解决这个问题,done
标志会在未来的某个事件中改变。因此,while
您将在将来为某些相关事件注册一个事件处理程序并在那里完成您的工作,而不是一个旋转循环。在绝对最坏的情况下,您可以设置一个循环计时器和“轮询”来经常检查标志,但几乎在每种情况下,您都可以为实际事件注册一个事件处理程序,这将导致done
标志更改并执行你的工作。知道其他代码想知道什么时候发生变化的正确设计的代码甚至可以提供自己的事件侦听器和自己的通知事件,人们可以注册感兴趣的事件,甚至只是一个简单的回调。