【问题标题】:Node.js setImmediate executed before I/O callbacks (Event Loop)Node.js setImmediate 在 I/O 回调之前执行(事件循环)
【发布时间】:2017-11-15 08:50:29
【问题描述】:
看看下面的代码:
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 回调之前执行,我是否遗漏了什么?
【问题讨论】:
标签:
javascript
node.js
event-loop
【解决方案1】:
您期望的结果需要 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
你可以做什么:
- 您可以使用 fs.stat 的同步版本。但是,尽管使用起来很舒服,但它会降低脚本的吞吐量,因为您将在 fs.stat 运行期间阻止脚本的执行。因此,如果您必须经常运行这部分代码,请使用以下方法之一!
- 您可能需要查看“await”以异步但按顺序运行代码
- 如果完成顺序对您来说并不重要,您也可以简单地使用 Promises 包装两个 fs.stat 调用。然后只做一个 Promise.all。或者您可以使用 async(一个库),它提供了许多处理异步性的功能
- ...
【解决方案2】:
setImmediate 不会等待所有 IO 操作完成。它只是优先考虑 IO 回调。在您在这里调用setImmediate 时,fs.stat 调用还没有完成,因此它们的回调还没有安排到事件循环中。