Node.js的process.nextTick(callback)理解

 

Node.js是單線程的,基於事件循環,非阻塞 IO的。事件循環中使用一個事件隊列,在每一個時間點上,系統只會處理一個事件,即便電腦有多個CPU核心,也沒法同時並行的處理多個事件。所以,node.js適合處理I/O型的應用,不適合那種CPU運算密集型的應用。在I/O型的應用中,給每個輸入輸出定義一個回調函數,node.js會自動將其加入到事件輪詢的處理隊列裏,當I/O操做完成後,這個回調函數會被觸發系統會繼續處理其餘的請求。 javascript

在這裏用debuggable.com上的那個文章中的一段比喻來說,很是容易理解。以下: java

咱們寫的js代碼就像是一個國王,而nodejs給國王提供了不少僕人。早上,一個僕人叫醒了國王,問他有什麼須要。國王給他一份清單,上面列舉了全部須要完成的任務,而後睡回籠覺去了。當國王回去睡覺以後,僕人才離開國王,拿着清單,給其它的僕人一個個佈置任務。僕人們各自忙各自的去了,直到完成了本身的任務後,纔回來把結果稟告給國王。國王一次只召見一我的,其它的人就在外面排着隊等着。國王處理完這個結果後,可能給他佈置一個新的任務,或者就直接讓他走了,而後再召見下一我的。等全部的結果都處理完了,國王就繼續睡覺去了。直接有新的僕人完成任務後過來找他。這就是國王的幸福生活。 node

process.nextTick(callback) c++

功能:在事件循環的下一次循環中調用 callback 回調函數。效果是將一個函數推遲到代碼書寫的下一個同步方法執行完畢時異步方法的事件回調函數開始執行時;與setTimeout(fn, 0) 函數的功能相似,但它的效率高多了。 git

基於node.js的事件循環分析,每一次循環就是一次tick,每一次tick時,v8引擎從事件隊列中取出全部事件依次進行處理,若是遇到nextTick事件,則將其加入到事件隊尾,等待下一次tick到來時執行;形成的結果是,nextTick事件被延遲執行;如下是nextTick源碼 github

從這幾行代碼中,咱們能夠看出不少信息: 多線程

  1. nextTick的確是把某任務放在隊列的最後(array.push)
  2. nodejs在執行任務時,會一次性把隊列中全部任務都拿出來,依次執行
  3. 若是所有順利完成,則刪除剛纔取出的全部任務,等待下一次執行
  4. 若是中途出錯,則刪除已經完成的任務和出錯的任務,等待下次執行
  5. 若是第一個就出錯,則throw error

下面看一下應用場景(包含計算密集型操做,將其進行遞歸處理,而不阻塞進程): 異步

  1. var http = require('http');
  2. var wait = function (mils) {
  3.     var now = new Date;
  4.     while (new Date - now <= mils);
  5. };
  6. function compute() {
  7.     // performs complicated calculations continuously
  8.     console.log('start computing');
  9.     wait(1000);
  10.     console.log('working for 1s, nexttick');
  11.     process.nextTick(compute);
  12. }
  13. http.createServer(function (req, res) {
  14.     console.log('new request');
  15.     res.writeHead(200, {'Content-Type': 'text/plain'});
  16.     res.end('Hello World');
  17. }).listen(5000, '127.0.0.1');
  18. compute();

一、其中compute是一個密集計算的函數,咱們把它變爲可遞歸的,每一步須要1秒(使用wait來代替密集運行)。執行完一次後,經過process.nextTick把下一次的執行放在隊列的尾部,轉而去處理已經處於等待中的客戶端請求。這樣就能夠同時兼顧兩種任務,讓它們都有機會執行。 函數

關於node.js中處理計算密集型,能夠參考如下幾種方法: oop

  • c/c++的addon來實現,在須要進行cpu密集型計算的地方,把js代碼改寫成c/c++代碼;對於不熟悉C++代碼,成本較高
  • 使用cluster建立多進程處理,但編碼複雜度比較高;
  • 讓node支持多線程模型的模塊:threads_a_gogogithub地址:https://github.com/xk/node-threads-a-gogo(比較好用一些,參考介紹

 

二、另外:異步模型的關係,致使某些代碼的執行可能先於它們所須要的條件完成以前,因此將這些須要先置條件的代碼放入到一個回調函數中,而後放入到下一個事件循環的頂層。那麼這些代碼就不會被馬上執行了,而是在下一輪事件啓動以前等待,啓動後在進行執行。

 

範例:

 

var MyConstructor = function() { ... process.nextTick(function() { self._continue(); }); };   MyConstructor.prototype.__proto__ = EventEmitter.prototype;   MyConstructor.prototype._continue = function() { // without the process.nextTick // these events would be emitted immediately // with no listeners. they would be lost. this.emit('data', 'hello'); this.emit('data', 'world'); this.emit('end'); };   function(req, res, next) { var c = new MyConstructor(...); c.on('data', function(data) { console.log(data); }); c.on('end', next); }
相關文章
相關標籤/搜索