在I / O回调之前执行的Node.js setImmediate(事件循环)

时间:2017-06-13 14:01:58

标签: javascript node.js event-loop

看看以下代码:

var fs = require('fs');
var pos = 0;

fs.stat(__filename, function() {
 console.log(++pos + " FIRST STAT");
});

fs.stat(__filename, function() {
 console.log(++pos + " LAST STAT");
});

setImmediate(function() {
 console.log(++pos + " IMMEDIATE")
})

执行此代码时,会显示以下结果:

enter image description here

正如Node.js documentation所解释的,setImmediate在I / O回调之后执行,但是在这个例子中,setImmediate正在I / O回调之前执行,我错过了什么吗?

2 个答案:

答案 0 :(得分:4)

您期望的结果将需要fs.stat方法即时返回 - 基本上在当前事件循环结束之前。但是你的磁盘需要2ms才能完成I / O操作。有足够的时间来完成相当多的事件循环。现在最有可能发生的事情是:

Loop 0 starts
fs.stat called
fs.stat called
immediate callback queued
Loop 0 ends
Loop 1 starts
immediate callback gets called
Loop 1 ends
Loop 2 starts
fs.stat completes, I/O callback queued
fs.stat completes, I/O callback queued
Loop 2 ends
Loop 3 starts
fs.stat I/O callback gets called
fs.stat I/O callback gets called

实际上没有人甚至保证fs.stat 1在fs.stat2之前完成。所以您发布的结果也可能是

1 IMMEDIATE
2 LAST STAT
3 FIRST STAT

你能做什么:

  1. 您可以使用fs.stat的同步版本。但是,尽管使用起来很舒服,但它会降低脚本的吞吐量,因为在fs.stat运行时会阻止脚本的执行。因此,如果必须经常运行这部分代码,请使用以下方法之一!
  2. 您可能需要查看" await"运行代码异步但按顺序
  3. 如果完成顺序对您无关紧要,您也可以简单地使用Promises来包装两个fs.stat调用。然后做一个Promise.all。或者你可以使用async(一个库)来提供很多处理异步性的功能
  4. ...

答案 1 :(得分:1)

setImmediate不会等待所有IO操作完成。它仅优先考虑IO 回调。当您在此处调用setImmediate时,fs.stat调用尚未完成,因此尚未为事件循环调度其回调。