使用 setImmediate 產生的腳本
參加過我關於 JavaScript 性能演講的人都熟悉我使用 setTimeout()
的傾向 將長腳本分解成更小的塊。使用 setTimeout()
時 ,您正在更改某些代碼的執行時間,從而有效地讓 UI 線程執行已排隊的任務。例如,您可以通過以下方式指示一些代碼在 50ms 後添加到 UI 線程隊列中:
setTimeout(function(){
//do something
}, 50)
所以在 50ms 之後,這個函數被添加到隊列中,並在輪到它時立即執行。對 setTimeout()
的調用 有效地讓當前的 JavaScript 任務完成,從而可以進行下一次 UI 更新。
問題
儘管我一直非常支持使用 setTimeout()
通過這種方式,這種技術存在一些問題。首先,跨瀏覽器的計時器分辨率各不相同。 Internet Explorer 8 及更早版本的計時器分辨率為 15.6 毫秒,而 Internet Explorer 9 及更高版本以及 Chrome 的計時器分辨率為 4 毫秒。所有瀏覽器都強制執行 setTimeout()
的最小延遲 ,所以 setTimeout(fn, 0)
實際是0ms後執行,是定時器解析後執行。
另一個問題是電源使用。管理計時器會耗盡筆記本電腦和移動設備的電池。 Chrome 曾嘗試將計時器分辨率降低到 1 毫秒,然後才發現它會損害筆記本電腦的電池壽命。最終,決定回到 4 毫秒的計時器分辨率。此後,其他瀏覽器也紛紛效仿,儘管許多後台選項卡的節流計時器分辨率為 1 秒。微軟發現將定時器分辨率降低到 1ms 可以將電池運行時間減少 25%。事實上,Internet Explorer 9 在筆記本電腦使用電池運行時將計時器分辨率保持在 15.6 毫秒,而在插入電源時僅增加到 4 毫秒。
setImmediate() 函數
W3C Web 性能工作組的 Efficient Script Yielding 規範定義了一個新函數來實現這種腳本分解,稱為 setImmediate()
. setImmediate()
function 接受單個參數,該參數是要執行的函數,它會插入該函數以在 UI 線程空閒時立即執行。基本用法:
var id = setImmediate(function(){
//do something
});
setImmediate()
函數返回一個 ID,可用於通過 clearImmediate()
取消調用 如有必要。
也可以將參數傳遞到 setImmediate()
函數參數通過在末尾包含它們:
setImmediate(function(doc, win){
//do something
}, document, window);
以這種方式傳遞附加參數意味著您不必總是使用帶有 setImmediate()
的閉包 以便為執行函數提供有用的信息。
優勢
什麼setImmediate()
確實使瀏覽器無需為此過程管理計時器。瀏覽器可以簡單地等待 UI 隊列清空,然後插入新的 JavaScript 任務,而不是等待系統中斷,這會消耗更多的電量。 Node.js 開發人員可能會從 process.nextTick()
開始識別此功能 在那種環境中做同樣的事情。
另一個優點是指定的函數在更短的延遲後執行,無需等待下一個計時器滴答聲。這意味著整個過程的完成速度比使用 setTimeout(fn, 0)
快得多 .
瀏覽器支持
目前,只有 Internet Explorer 10 支持 setImmediate()
, 它通過 msSetIntermediate()
因為規範尚未最終確定。 Internet Explorer 10 Test Drive 站點有一個 setImmediate()
顯示使用新方法改進性能的示例。該示例使用延遲對值進行排序,同時直觀地顯示排序的當前狀態。此示例需要 Internet Explorer 10。
未來
我很看好setImmediate()
功能及其對 Web 開發人員的價值。使用計時器來生成腳本是一種 hack,當然,使用官方的方式來生成腳本對於性能來說是一個巨大的勝利。我希望其他瀏覽器能很快接受這個實現,這樣我們就可以盡快開始使用它了。