为什么while循环会阻塞事件循环?

cod*_*boy 15 javascript node.js

以下示例在Node.js书中给出:

var open = false;

setTimeout(function() {
  open = true
}, 1000)

while (!open) {
  console.log('wait');
}

console.log('open sesame');
Run Code Online (Sandbox Code Playgroud)

作者解释说明while循环阻止执行的原因:

Node永远不会执行超时回调,因为事件循环停留在第7行的while循环中,永远不会让它有机会处理超时事件!

但是,作者没有解释为什么会在事件循环的上下文中发生这种情况或者真正发生在幕后的事情.

有人可以详细说明吗?节点为什么会卡住?如何更改上面的代码,同时保留while控制结构,以便不阻止事件循环,并且代码将按照人们可能合理预期的方式运行; 等待将在setTimeout火灾前记录仅1秒,然后在记录"打开芝麻"后退出该过程.

关于IO和事件循环和回调这个问题的答案等通用解释并没有真正帮助我理解这一点.我希望直接引用上述代码的答案会有所帮助.

jfr*_*d00 23

这真的很简单.在内部,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!");
Run Code Online (Sandbox Code Playgroud)

有些人可能逻辑上认为while循环将旋转直到计时器触发,然后计时器将更改doneto 的值,true然后while循环将完成,并且console.log()最后将执行.那不会发生什么.这实际上是一个无限循环,并且console.log()永远不会执行该语句.

问题是,一旦你进入while()循环中的旋转等待,没有其他Javascript可以执行.因此,想要更改变量值的计时器done无法执行.因此,while循环条件永远不会改变,因此它是一个无限循环.

这是JS引擎内部发生的事情:

  1. done 变量初始化为 false
  2. setTimeout() 从现在起安排计时器事件1秒钟
  3. while循环开始旋转
  4. 进入while循环旋转1秒后,计时器在内部激活JS引擎,并将计时器回调添加到事件队列中.这可能发生在JS引擎内部的不同线程上.
  5. while循环保持旋转,因为done变量永远不会改变.因为它继续旋转,JS引擎永远不会完成这个执行线程,永远不会从事件队列中提取下一个项目.


dan*_*y74 8

这是一个很好的问题,但我找到了解决方法!

var sleep = require('system-sleep')
var done = false

setTimeout(function() {
  done = true
}, 1000)

while (!done) {
  sleep(100)
  console.log('sleeping')
}

console.log('finally, the done value changed!')
Run Code Online (Sandbox Code Playgroud)

我认为它有效,因为system-sleep不是旋转等待。

  • 我想知道除了所有的 PHD 演讲之外,没有人赞成这个页面上唯一有效的解决方案。 (3认同)
  • 我后来发现这是唯一有效的解决方案,但它只有效,因为它是一个 C++ hack,这在 Node.js 中应该是不可能的 - 这将适用于大多数平台,但是,它会在某些平台上失败,所以应谨慎使用 - 但是非常适合开发人员使用 (2认同)