2014-10-09 60 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