1. 程式人生 > 其它 >nodejs學習隨筆3--I/O非同步

nodejs學習隨筆3--I/O非同步

非I/O非同步的API

setTimeout(),setInterval(),setImmediate(),process.nextTick()

1,定時器

Node中的定時器和瀏覽器中用法一致。區別在於:在Node中,執行到setTimeout或setInterval的時候,會生成一個定時器,呼叫setTimeout或setInterval建立的定時器會被插入到定時器觀察者內部的一個紅黑樹中。每次事件迴圈,會從這個紅黑樹中迭代取出定時器物件,檢查是否超過定時時間,如果超過了,就形成一個事件,它的回撥函式立即執行。

換句話說,執行定時器,就會有一個定時器觀察者,每次事件迴圈,觀察者就會去看定時器到點兒沒,到了就執行回撥。雖然每次事件迴圈很快,但是也會存在某個任務佔用CPU時間片較長,然後超過了定時器的時間,導致等觀察者去檢查的時候,已經過了時間了。

這個和瀏覽器機制類似,但是瀏覽器好像沒有觀察者這一概念(沒有在event loop文件裡看到)

2,process.nextTick()

這個方法的效果就跟它的命名一樣,將回調函式推入到下一次Tick,相比於定時器,它的複雜度較低,更高效,因為它不需要迭代紅黑樹,而是直接將回調函式放入佇列中。

至於它的執行速度,知乎上討論的比較激烈,我站隊這個說法:

3,setImmediate

也是將回調函式延遲執行,但是優先順序方面,process.nextTick()中的回撥函式執行的優先順序要高於setImmediate()。這裡的原因是在於事件迴圈對觀察者的檢查是有先後順序的,process.nextTick()屬於idle觀察者,setImmediate()屬於check觀察者。在每一個輪迴圈檢查中,idle觀察者先於I/O觀察者,I/O觀察者先於check觀察者。

在具體實現上,兩者也有差異,process.nextTick()的回撥函式是在一個數組中,而setImmediate()的結果則是儲存在連結串列中。在行為上,process.nextTick()在每輪迴圈中會將陣列的回撥函式全部執行完,而setImmediate()在每輪迴圈中執行連結串列中的一個回撥函式。

1 2 3 4 5 6 7 8 9 10 setImmediate(function(){ console.log('setImmediate 1'); process.nextTick(function(){ console.log('process 1') }) });
setImmediate(function(){ console.log('setImmediate 2') });

上面程式碼執行結果:

1 2 3 setImmediate 1 process 1 setImmediate 2

可以看出執行完setImmediate 1以後並沒有執行setImmediate 2,而是執行了下一輪迴圈,然後先執行了process 1,然後再執行了setImmediate 2。這樣設計的目的是為了保證每輪迴圈能夠較快地執行結束,防止CPU佔用過多而阻塞後續I/O呼叫的情況。看來process.nextTick還真的是微任務,而且不光是這樣,在node環境下,process.nextTick的執行優先順序高於promise的回撥。

事件驅動的實質:即通過主迴圈加事件觸發的方式來執行程式