process.nextTick, setImmediate, setTimeout, requestAnimationFrame

標題這幾個 API 是感覺功能有些接近的東西,process.nextTick是 node 的,setImmediate是微軟提出但是只有 IE 和 node 有實作,setTimeout是最老牌的,感覺後面給它 0ms 延遲,效果和其他幾個很像,requestAnimationFrame則是更新畫面作動畫時用的新 API,那細部這幾個 API 有什麼差異呢?

要繼續之前可能要先了解一下 JavaScript Event Loop,和 Timer 還有瀏覽器更新 UI 的關係,可以參考 John Resig 的 How JavaScript Timers Work 這篇文章,標題那四個 API 除了最後一個 requestAnimationFrame 一定是等到瀏覽器要更新 UI 了才會呼叫到,然後螢幕有個更新頻率,不管怎樣快都不會到千分之一秒叫一次,所以它基本上就是最慢的。

那前面三個有什麼差別呢?先來看看setImmediatesetTimeout,根據微軟的說法,因為 setTimeout 有個最小的 4ms 延遲,所以他們設計了 setImmediate 這個完全無延遲的 API 介面出來,不過其實根據 whatwg 的 spec,其實要 nesting 的 setTimeout call 才要加上這個 4ms 最小延遲,也就是在 setTimeout 裡面又呼叫 setTimeout 這種狀況,而且要超過五層,會這樣設計是為了避免連續的 setTimout 會造成 UI 卡住,所以我猜是微軟的 setTimeout 實作不正確,而 WebkitFirefox 也因此都沒實作它,總之要是正確的作 setTimout,不要連續呼叫超過五層,那他和 setImmediate 應該會是一樣快的,順代一題,微軟那個比較的網頁上就沒有設成 0ms 的 case 可以看在其他瀏覽器上的表現。

最後一個是process.nextTick了,這是 node 才有的 API,它和後面三個的作法不太一樣,速度也是所有 API 裡面最快的,實際上它不是把 function 丟到 timer 的 queue 裡面等,而是跟系統說,現在這個 all stack 結束後,立即去執行這些 function,也就是它其實是獨立的 queue,所有丟到 nextTick 裡面的 function 都執行完後,才輪的到 setImmediate 或是其他 UI、系統 IO 的份,而這個 queue 是先進先出,所以其實還蠻好用的,難怪在 node 裡面感覺大家用得很兇,不過要注意。

回頭看一下 setImmediate,其實網路上也是有不少 polyfill 提供,這些實作都是用 postMessage 來避開 setTimeout 會產生的 4ms 最小延遲,無法使用 postMessage 時會 fallback 到 setTimout。其實會看這些東西是因為 browserify 的關係,因為 browserify 有說會提供 node 的東西到瀏覽器上,像是process.nextTick,好奇了一下setImmediate有沒有也提供,結果看起來目前是沒有,不過深入研究之後也發現其實不是真的有這個需要就是了。


更之前的文章