Node.js 中 setTimeout(f1, 0) 與 setImmediate(f2) ,f1 f2的執行順序是隨機的嗎,為什麼呢?
測試代碼:
多次運行結果:
瀉藥
真心不會 node 啊……
能假裝沒看見么,剛改完 PHP 回來,而且都大半夜了 = =|||佔個坑明兒再說?洗洗回來,還是忍不住簡單寫寫。話說還真是得看文檔。但是更關鍵的是得看源碼,哭。否則也不好找文檔哪兒說。怎麼看代碼先不寫了。困,老了,實在扛不住。ps:node 代碼還老改來改去,每次都得重找還。
setImmediate 先說這個,可以參考這裡的部分:Process.nextTick 和 setImmediate 的區別? - Node.js但是,由於 現在 node 代碼又改來改去,說代碼的部分就不用細看了。主要看 libuv 的 uv_check_t , setImmediate 最終是調用的它。根據文檔說明:Check handles will run the given callback once per loop iteration, right after polling for i/o.
這貨會在IO處理之後回調。setTimout 最終調用 libuv 的 uv_timer_start。這玩意有個陷阱,說是如果timout 是 0 就下一個事件循環調用。If timeout is zero, the callback fires on the next event loop iteration.
但是吧,去看 node 里的 times.js 實現。exports.setTimeout = function(callback, after) {
var timer;
after *= 1; // coalesce to number or NaN
if (!(after &>= 1 after &<= TIMEOUT_MAX)) { after = 1; // schedule on next tick, follows browser behaviour } timer = new Timeout(after); ... }
timeout 為 0 時候就給規約為 1 了。
所以呢,他還是得在事件循環時候參與計時,如果計時達到就觸發回調。那好,一個事件循環里要按順序整多少事兒呢?根據官方文檔可知:- 先跑定時器 due
- ……
- 然後 idle (也就是nextTick)
- ……
- 然後IO
- 之後才到 check (也就是 setImmediate)
- ……
- 一次循環完
然後跑啊跑,到 check setImmediate 必然執行。
最後跑到一次事件循環結束。下次事件循環開始。跑到setTimeout 0(其實是1),時間到了(或過了),回調立即觸發。這就是 setImmediate 先 setTimeout 0 後的情況。同樣,取決於事件循環第一次定時器時間比對,如果 setTimeout 0(其實是1)在當前事件循環恰好時間到了(或過了),回調立即觸發。然後跑啊跑,到 check setImmediate 必然執行。這就是 setTimeout 0 先 setImmediate 後的情況。偶覺得是說清楚了,收工碎叫。ps:1、libuv 文檔:Welcome to the libuv API documentation
2、居然看見有發阮大文章的……內個吧,起碼發的內篇不真……具體對比看吧,不說了,怕被噴3、如果要跟代碼,看 timers.js 和 http://timer_wrap.cc 基本就能跟差不多了,再跟下去得去 libuv 里找。======================= 補充 =============================有說這例子里 console.log 輸出是非同步的,所以測試代碼有問題,才導致這種情況。根據 node 文檔,說通常是同步的,這詞太含糊,得實際跟下代碼。然後跟了下代碼。關鍵流程是:在控制台下,會走入 TTY (中斷)判斷然後 TTY 下會走到 stream_wrap.c 的 StreamWrapCallbacks::TryWrite 輸出 (node.js)之後進入 uv_try_write (libuv) -&> uv__write -&> write 輸出
write 是 C 標準庫函數整個過程無任何非同步。所以測試代碼沒問題。如果不放心把 consoel.log 換成 arr.push這肯定是同步的然後看 arr 數組順序一樣是不固定的。1. 請看文檔
2. 請自己寫個代碼實際測試下
3. 善用搜索(google、stackoverflow、GitHub)以上三個都做了還找不到答案再提問。
[補充]你的測試代碼有問題。問題在哪兒自己想想看。好像就是就是不確定的,這裡有篇博文,可以了解一下event loop:
http://www.ruanyifeng.com/blog/2014/10/event-loop.html純搬運了……setTimeout 將任務加入到了事件循環中,而nextTick加入到了回調隊列中
setTimeout不一定是什麼順序,不過nextTick和setImmediate是確定的
推薦閱讀:
※為什麼 Node.js 不給每一個.js文件以獨立的上下文來避免作用域被污染?
※為什麼nodejs不給每一個.js文件以獨立的上下文來避免作用域被污染?
※nodejs中,zlib.gzip系列純cpu計算函數為什麼會有非同步版本?
※es6 import from xx , 是怎麼實現找到 node_modules目錄下的?
TAG:Nodejs |