2014-10-09 61 views
10

我正在试验事件循环。首先我从这个简单的代码开始阅读和打印文件的内容:了解Node.js事件循环。 process.nextTick()从不调用。为什么?

var fs = require('fs'); 
var PATH = "./.gitignore"; 

fs.readFile(PATH,"utf-8",function(err,text){ 
    console.log("----read: "+text); 
}); 

然后我把它放到一个无限循环中。在这种情况下,readFile函数从不执行。如果我没有弄错,那是因为Node的单线程忙于迭代而不让I/O调用被执行。

while(true){ 
    var fs = require('fs'); 
    var PATH = "./.gitignore"; 

    fs.readFile(PATH,"utf-8",function(err,text){ 
     console.log("----read: "+text); 
    }); 
} 

所以,我想,这样的I/O调用分配与循环交织过程的时间做一些事情。我尝试使用process.nextTick()但它不起作用:

while(true){ 
    process.nextTick(function(){ 
     fs.readFile(PATH,"utf-8",function(err,text){ 
      console.log("----read: "+text) 
     }); 
    }); 
} 

为什么它不工作,我怎么能做到这一点?

回答

24

因为你的while循环仍在运行。这只是在下一个勾号中无限添加的东西。如果你放弃它,你的节点进程会在内存耗尽时崩溃。

当你使用异步代码时,你的正常循环和控制结构往往会让你失望。原因是它们在事件循环的一个步骤中同步执行。直到发生事件再次控制事件循环,没有任何'nextTick'会发生。

想想这样,当代码运行时,您处于事件循环的传递B中。当您致电

process.nextTick(function foo() { do.stuff(); })' 

您正在将foo添加到“开始传递事件循环C之前要做的事情”列表中。每次调用nextTick时,都会在列表中再添加一个内容,但在同步代码完成之前,它们都不会运行。

你需要做的是在你的回调中创建'做下一件事'链接。考虑链接列表。

// var files = your list of files; 
function do_read(count) { 
    var next = count+1; 
    fs.readFile(files[count], "utf-8", function(err,text) { 
     console.log("----read: " + text); 

     if (next < files.length) { 
      // this doesn't run until the previous readFile completes. 
      process.nextTick(function() { do_read(next) }); 
     } 
    }); 
} 
// kick off the first one: 
do_read(files[0], 0); 

(显然这是一个人为的例子,但你的想法)

这使得每个“下一个文件”添加到“nextTick”待办事项队列前一个只有后已经完全处理。

TL; DR:在大多数情况下,你不希望直到前一件事是完成

希望帮助启动它做接下来的事情!

+1

优秀的解释,谢谢JayKuri! – codependent 2014-10-10 06:55:20

+0

非常好的解释,你可以给一些证明来验证你的关于process.nextTick的声明。像任何由节点或JavaScript文档。 – 2016-09-25 18:35:10

+0

优秀的解释 - 现在我明白了... – Guihgo 2017-02-12 05:00:04