2017-06-13 126 views
5

看看下面的代码执行:Node.js的setImmediate前I/O回调(事件循环)

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回调后执行,但在本例中,在I/O回调之前正在执行setImmediate,我错过了什么吗?

回答

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.stat2之前fs.stat 1点完成。所以,你已经公布的结果也可能是

1 IMMEDIATE 
2 LAST STAT 
3 FIRST STAT 

你可以做什么:

  1. 可以使用fs.stat的同步版本。但是,尽管使用起来很舒服,但会降低脚本的吞吐量,因为您将在fs.stat运行时阻止脚本的执行。所以如果你不得不经常运行这部分代码,请使用以下方法之一!
  2. 你可能想看看“await”运行的代码异步,但在序列
  3. 如果完成的顺序并不重要,你也可以简单地使用承诺包都fs.stat电话。然后做一个Promise.all。或者你可以使用异步(一个库),提供了很多功能来处理异步性
  4. ...
1

setImmediate不等待所有IO操作完成。它仅优先于IO 回调。在您拨打setImmediate时,fs.stat调用还没有完成,因此它们的回调没有安排在事件循环中。