以下示例在Node.js书中给出:
var open = false; setTimeout(function() { open = true }, 1000) while (!open) { console.log('wait'); } console.log('open sesame');
解释了while循环为何阻止执行时,作者说:
节点将永远不会执行超时回调,因为事件循环卡在了此循环中,而循环在第7行上开始了,因此永远不会给它处理超时事件的机会!
但是,作者没有解释为什么这是在事件循环的背景下发生的,还是在幕后真正发生了什么。
有人可以详细说明吗?为什么节点卡住?以及如何在保持while控制结构不变的情况下更改上述代码,以使事件循环不会被阻塞,并且代码将像人们合理预期的那样运行;在setTimeout发生火灾之前,只会记录1秒钟的等待时间,然后在记录“打开芝麻”后退出该过程。
while
setTimeout
诸如此类的关于IO和事件循环以及回调的问题的答案之类的通用解释并不能真正帮助我合理化。我希望直接引用上述代码的答案会有所帮助。
真的很简单。在内部,node.js包含以下类型的循环:
如果在某个时刻事件队列中什么都没有,则进入睡眠状态直到事件队列中放置了某些东西。
因此,如果一段Javascript处于while()循环中,则该任务没有完成,并且按照上述顺序,在完成之前的任务之前,不会从事件队列中挑出任何新东西。因此,一个很长甚至永远运行的while()循环只会加重工作量。因为Javascript一次仅运行一个任务(用于JS执行的单线程),所以如果一个任务在while循环中旋转,那么其他任何事情都将无法执行。
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循环将旋转直到计时器触发,然后计时器将更改doneto 的值,true然后while循环将完成,最后的while console.log()将执行。那不会发生。实际上,这将是一个无限循环,并且该console.log()语句将永远不会执行。
done
true
console.log()
问题是,一旦您进入while()循环等待循环,就无法再执行其他Javascript。因此,想要更改变量值的计时器done无法执行。因此,while循环条件永远不会改变,因此它是一个无限循环。
这是JS引擎内部发生的事情:
false
setTimeout()
node.js is an event driven environment. To solve this problem in a real world application, the done flag would get changed on some future event. So, rather than a spinning while loop, you would register an event handler for some relevant event in the future and do your work there. In the absolute worst case, you could set a recurring timer and “poll” to check the flag ever so often, but in nearly every single case, you can register an event handler for the actual event that will cause the done flag to change and do your work in that. Properly designed code that knows other code wants to know when something has changed may even offer its own event listener and its own notification events that one can register an interest in or even just a simple callback.