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

Node.js setImmediate executed before I/O callbacks (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")
})

当我执行这段代码时,会显示以下结果:

正如Node.js documentation 解释的那样,setImmediate 是在I/O 回调之后执行的,但是在这个例子中setImmediate 是在I/O 回调之前执行的,我是不是漏掉了什么?

setImmediate 不等待所有 IO 操作完成。它只是优先考虑 IO callbacks。当您在这里调用 setImmediate 时,fs.stat 调用还没有完成,因此它们的回调还没有安排到事件循环中。

您期望的结果需要 fs.stat 方法立即 return - 基本上在当前事件循环结束之前。但是您的磁盘将需要 2 毫秒来完成 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。或者你可以使用异步(一个库),它提供了很多处理异步的特性
  4. ...