最佳化 JavaScript 執行作業

JavaScript 經常會觸發視覺調整。有時直接透過樣式操弄,有時會導致視覺上發生變化,例如搜尋或排序資料。JavaScript 運作狀況不佳或長時間執行,是造成效能問題的常見原因。請盡可能降低對控製造成的影響。

保羅路易斯
Paul Lewis

JavaScript 經常會觸發視覺調整。有時直接透過樣式操弄,有時則是透過計算或排序資料等視覺方式改變。JavaScript 運作不良或長時間執行是效能問題的常見原因。請盡可能降低對控製造成的影響。

JavaScript 效能剖析可以是一件藝術,因為您編寫的 JavaScript 與實際執行的程式碼不同。新型瀏覽器會使用 JIT 編譯器以及所有最佳化和秘訣,盡可能讓您以最快的速度執行,進而大幅變更程式碼的動態。

不過即使如此,您還是可以指定一些措施,協助應用程式有效執行 JavaScript。

摘要

  • 避免在視覺更新中使用 setTimeout 或 setInterval;請一律改用 requestAnimationFrame。
  • 將長時間執行的 JavaScript 從主執行緒移至網路工作站。
  • 使用微任務變更多個影格的 DOM 變更。
  • 使用 Chrome 開發人員工具的時間軸和 JavaScript 分析器,評估 JavaScript 的影響。

使用 requestAnimationFrame 變更視覺元素

如果畫面上發生視覺變化,您希望在適當的時機在瀏覽器中 (也就是畫面開始時) 執行工作。確保 JavaScript 在影格開始時執行的唯一方法是使用 requestAnimationFrame

/**
    * If run as a requestAnimationFrame callback, this
    * will be run at the start of the frame.
    */
function updateScreen(time) {
    // Make visual updates here.
}

requestAnimationFrame(updateScreen);

架構或範例可能會使用 setTimeoutsetInterval 執行動畫等視覺變更,但問題是,回呼會在影格的「某個時間點」執行,且通常會導致我們遺漏影格,導致資源浪費。

導致瀏覽器錯過頁框的 setTimeout。

事實上,jQuery 使用 setTimeoutanimate 行為。已在第 3 版中改為使用 requestAnimationFrame。如果您使用的是舊版 jQuery,可以修補程式碼以使用 requestAnimationFrame,強烈建議您這麼做。

降低複雜性或使用網路工作站

JavaScript 會在瀏覽器的主要執行緒上執行,緊接在樣式計算、版面配置,甚至在許多情況下繪製。如果 JavaScript 執行時間很長,就會封鎖其他工作,這或許會導致影格遺漏。

建議您規劃 JavaScript 的執行時間和持續時間。舉例來說,如果您正在進行捲動等動畫,則理想做法是將 JavaScript 控制在 3-4ms 的地區。超過這個期限後,你可能會浪費太多時間。但如果處於閒置狀態,可以進一步放寬作業時間。

在許多情況下,您可以將純運算工作移至網路工作站,例如不需要 DOM 存取權時。在載入和模型產生時,資料操縱或週遊 (例如排序或搜尋) 通常適合這個模型。

var dataSortWorker = new Worker("sort-worker.js");
dataSortWorker.postMesssage(dataToSort);

// The main thread is now free to continue working on other things...

dataSortWorker.addEventListener('message', function(evt) {
    var sortedData = evt.data;
    // Update data on screen...
});

並非所有工作都能適用於這個模型:網路工作處理人員沒有 DOM 存取權。如果工作必須在主執行緒中,不妨考慮採用批次處理方法,將大型工作區隔為小型工作 (每項工作都只需幾毫秒),然後於每個影格的 requestAnimationFrame 處理常式中執行。

這個方法會帶來使用者體驗和 UI 的影響,您必須使用進度或活動指標,確保使用者知道工作正在處理中。在任何情況下,這個方法都能讓應用程式的主要執行緒保持免費,進而持續回應使用者互動。

瞭解 JavaScript 的「頁框稅金」

評估架構、程式庫或自己的程式碼時,請務必根據個別影格評估執行 JavaScript 程式碼的費用。在進行轉換或捲動等重要效能動畫時,這一點特別重要。

Chrome 開發人員工具的「效能」面板是評估 JavaScript 費用的最佳方式,一般而言,您會取得類似以下的低階記錄:

Chrome 開發人員工具的效能錄影

「Main」區段提供 JavaScript 呼叫的火焰圖,方便您分析確切呼叫的函式,以及每個函式花費的時間。

您可以利用這項資訊評估 JavaScript 對應用程式的效能影響,並開始找出並修正函式執行時間過長的任何熱點。如先前所述,您應該嘗試移除長時間執行的 JavaScript;如果無法這麼做,請將其移至網路工作站釋出主要執行緒,以便繼續處理其他工作。

如要瞭解如何使用「效能」面板,請參閱「開始使用分析執行階段效能」。

避免對 JavaScript 進行最佳化

您可能也知道,瀏覽器執行同一版本的執行速度比其他作業快 100 倍,例如要求元素的 offsetTop 比計算 getBoundingClientRect() 快速,但幾乎總是如此,只有在每個影格僅呼叫這類函式才會如此,因此一般來說,將焦點放在 JavaScript 效能的這方面。通常您只會儲存幾毫秒的結果。

如果您是開發遊戲或計算高昂成本的應用程式,那麼您可能會遇到本指南的例外情況,因為您通常會將大量計算納入單一影格中,這樣一切都有助於解決問題。

簡單來說,微型最佳化通常不會對應至您要建構的應用程式類型,因此請謹慎處理。