前面的話
前端日問,鞏固基礎,不打烊!!!
解答
首先兩者都是定時器,在node中有4種定時器:
- setTimeout
- setInterval
- setImmediate
- process.nextTick
在node中,I/O處理方面有自己的libuv引擎,libuv引擎中事件循環分爲6個階段:
- timers階段: 執行timer(setTimeout 、setInterval)的回調
- poll階段: 獲取新的I/O事件,適當的條件下node將阻塞在這裏。
- check階段: 執行setImmediate()的回調。
setTimeout是在timer階段,而setImmediate是在check階段。
ps:
在poll階段主要執行兩件事:執行I/O回調、處理隊列中的事件。
當事件循環在poll階段時:
1、如果poll隊列不爲空,則執行隊列中的回調;
2、 如果隊列中爲空,且有setImmediate回調要執行,就會立即停止poll階段,進入check階段執行setImmediate的回調;
3、 如果隊列爲空,並且沒有setImmediate回調要執行,poll階段將等待新的callback被加入。
4、如果有timer的話並且poll隊列爲空,則會檢查是否有timer超時,如果有的話就回到timer階段,執行相應的回調。
setTimeout與setImmediate區別
-
如果二者都從主模塊內調用,則計時器將受進程性能的約束。舉個例子,有如下代碼:
setTimeout(() => console.log(1)); setImmediate(() => console.log(2));
如果二者都從主模塊內調用,則計時器將受進程性能的約束。 輸出結果不一定,有可能先是1,也有可能先是2。
因爲setTimeout的第二個參數默認爲0,但實際上,Node做不到0秒,最少也要1毫秒。那麼進入事件循環後,如果沒到1毫秒,那麼timers階段就會跳過,進入check階段。
-
如果兩者在I/O週期內調用,始終先執行setImmediate回調。
const fs = require('fs'); fs.readFile(__filename, () => { setTimeout(() => { console.log('timeout'); }, 0); setImmediate(() => { console.log('immediate'); }); });
因爲I/O回調是在poll階段執行,當回調執行完畢之後隊列爲空,發現存在setImmediate的回調就會進入check階段,執行完畢後,再進入timer階段。