從 JavaScript 著手優化渲染效能

JavaScript 只是開發者撰寫的程式碼,而非實際執行的程式碼,這聽起來很奇怪,但其實是這樣的…現今 JavaScript 引擎會編譯開發者所撰寫的程式碼,優化而使其效能更好後,再到瀏覽器執行,而這個編譯引擎就是 JIT(Just in Time Compiler)。

瀏覽器渲染效能(Browser Rendering Performance)

圖片來源:Browser Rendering – Performance past the first page load

避免 Micro-optimization

有些人在嘗試撰寫效能佳的程式碼時,會思考這個問題「迴圈用 for 還是 while 比較好呢?」但我們並不知道 JavaScript 引擎如何看待這兩者,或說如何優化,所以有這種比較相似程式碼片段的焦慮是不必要的。

然而,若想改善效能,是可以從其他方面著手的,像是 Critical Rendering Path、requestAnimationFrame、使用工具 JavaScript Profiler 檢視瓶頸所在、使用 Web Workers 執行複雜運算、控管記憶體等。

requestAnimationFrame

使用 requestAnimationFrame,瀏覽器就能依照自身狀況優化動畫效能,而不像 setTimeoutsetInterval 可能中斷瀏覽器正在進行的工作,無法顧及 Browser Rendering Pipeline 到哪一個階段了,而導致畫面渲染時遺失了某些 Frame,在使用者看來就是發生顫動(Juddering)。

requestAnimationFrame in Browser Rendering Pipeline

圖片來源:Making a Silky Smooth Web

範例。

function animate() {
  // do something...
  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

現今瀏覽器只有 IE9 不支援 requestAnimationFrame,但沒關係,使用 polyfill 來補足即可。

JavaScript Profiler

Chrome Devtools 的 JavaScript Profiler 可檢視 JavaScript 程式碼的 function call stack 和花了多少時間來執行,或也可以使用 Performance 的 Timeline。JavaScript Profiler 位於 More tools > JavaScript Profiler。

JavaScript Profiler

JavaScript Profiler

Web Workers

關於 Web Workers 另外整理了一篇文章,可參考這裡

JS Memory Management

JavaScript 引擎會自動回收記憶體(Garbage Collection),但可能會造成某些 Frame 的遺失,而產生顫動(Juddering)。

若希望有效進行垃圾回收,以下有一些規則

如何觀察記憶體回收的情況?從 Chrome Devtools 的 Performace 頁籤打開 Memory 選項,即可看到 Memory Timeline。

這裡我們需要注意

若想觀察呼叫記憶體回收的時機和細節,可取消勾選 Memory,並在 Timeline 搜尋 GC。

若因為記憶體回收而顫動過於頻繁,那就要試圖找出原因,像是…某個 function 產生過多的垃圾,使得 JavaScript 引擎過度做記憶體回收。

More on Garbage Collection

備註

參考資料


requestAnimationFrame 關鍵轉譯路徑 效能調校 轉譯效能 Rendering Performance Critical Rendering Path Chrome DevTools javascript css3 animations css 前端效能 系列文