JavaScript 效能優化技巧分享
JavaScript 作為當前最為常見的直譯式指令碼語言,已經廣泛應用於 Web 應用開發中。為了提高Web應用的效能,從 JavaScript 的效能優化方向入手,會是一個很好的選擇。
本文從載入、上下文、解析、編譯、執行和捆綁等多個方面來講解 JavaScript 的效能優化技巧,以便讓更多的前端開發人員掌握這方面知識。
什麼是高效能的 JavaScript 程式碼?
儘管目前沒有高效能程式碼的絕對定義,但卻存在一個以使用者為中心的效能模型,可以用作參考:RAIL模型。
-
響應
如果你的應用程式能在100毫秒內響應使用者的操作,那麼使用者會認為該響應為即時的。這適用於可點選的元素,不適用於滾動或拖動操作。
-
動畫
在60Hz的顯示器上,我們希望動畫和滾動時每秒有60幀,這種情況下每幀大約為16ms。在這16ms的時間內,實際上只有8-10ms來完成所有工作,其餘時間則由瀏覽器的內部和其它差異佔據。
-
空閒工作
如果你有一個耗時很久,需要持續執行的任務時,請確保把它分成很小的塊,以便允許主執行緒對使用者的輸入操作做出反應。不應該出現一個任務延遲超過50ms的使用者輸入。
-
載入
頁面載入應該在1000毫秒內完成。在移動裝置上,這是一個很難達到的目標,因為它涉及到頁面的互動,而不僅僅是在螢幕上渲染和滾動。
- 如果移動網站的載入時間超過三秒,則會有53%的使用者放棄訪問
- 50%的使用者希望在不到2秒的時間內完成頁面載入
- 77%的移動網站需要10秒以上的時間來載入3G網路
- 19秒是3G網路上移動站點的平均載入時間
程式碼內容
你可能已經注意到了,最大的瓶頸是載入網站所需的時間。具體來說就是 JavaScript 的下載、解析、編譯和執行時間。除了載入更少的 JavaScript 檔案或者載入的更加靈活以外,看起來沒有其它辦法。
除去啟動網站之外,JavaScript 程式碼又是如何實際工作的呢?
在進行程式碼優化之前,請考慮你當前正在構建的內容。你正在建立的是一個框架還是一個 VDOM 庫?你的程式碼是否需要每秒執行數千次操作?你是否正在做一個對時間要求較為嚴格的庫來處理使用者輸入和/或動畫?如果沒有,你需要把時間和精力轉移到更有影響力的地方。
編寫高效能程式碼並不是那麼重要,因為對於巨集觀計劃通常沒有什麼影響。50k ops/s 聽起來好於 1k ops/s,但在大多數情況下整體時間並不會有所改變。
解析、編譯和執行
從根本上說,大多數 JavaScript 的效能問題,並不在於執行程式碼本身,而是在程式碼開始執行之前必須採取的一系列步驟。
我們在這裡討論抽象層次的問題。計算機上執行的大多數程式碼都是編譯後的二進位制格式。意思是說,除了所有的作業系統級別的抽象外,程式碼都可以在硬體上本地執行,不需要準備工作。
JavaScript 程式碼不是預編譯的,它在瀏覽器上是可讀的。
JavaScript 程式碼首先會被解析,也就是讀取並轉換成可用於編譯的計算機索引的結構,然後再被編譯成位元組碼,最後被編譯成機器碼,用於裝置/瀏覽器執行。
另一個非常重要的方面是:JavaScript 是單執行緒的,並且在瀏覽器的主執行緒上執行。這意味著一次只能執行一個程序。如果你的 DevTools 效能時間線充滿黃色峰值,同時 CPU 佔用率達到100%,則將出現丟幀的情況。這是滾動操作常出現的,也是很討厭的一種情況。
在 JavaScript 程式碼執行之前,需要完成所有的這些解析、編譯和執行工作。在 ChromeV8 引擎中,解析和編譯佔 JavaScript 執行總時間的50%左右。
所以在這部分中,應該瞭解兩件事情:
1. 雖然 JavaScript 解析的時間長度和包的大小不是完全線性的,但是需要處理的 JavaScript 越少,則所花時間越少。
2. 你使用的每一個 JavaScript 框架(React,Vue,Angular,Preact …)都是另一個抽象層次(除非它是一個預編譯的)。這不僅會增加你的包的大小,而且會讓你的程式碼變慢,因為你不是直接與瀏覽器通訊的。
有些方法可以緩解這種情況,比如使用 service workers 在後臺的另一個執行緒中執行部分工作,或者使用 asm.js 編寫更容易編譯機器指令的程式碼。
我們所能做的,就是避免使用 JavaScript 動畫庫。只有在使用常規的 CSS 轉換和動畫完全無法實現時,才去使用這些庫。
即使這些 JavaScript 動畫庫使用 CSS 轉換,合成屬性和 requestAnimationFrame( ),但是它們仍然執行在 JavaScript 的主執行緒上。基本上這些庫會使用內聯樣式每16ms訪問一次 DOM。你需要確保所有的 JavaScript 都在每幀8ms以內完成,才能保持動畫的平滑性。
另一方面,CSS 動畫和轉換會在主執行緒中執行,如果能夠高效執行,則能避免重新佈局/重排的情況出現。
考慮到大多數動畫都在載入或使用者互動的過程中執行,這可以為你的 web 應用程式提供非常重要的調整空間。
web Animations API 是一個即將到來的功能集,它能夠脫離主執行緒執行高效能的 JavaScript 動畫。但就目前而言,還需要繼續使用 CSS 轉換等技術。
捆綁尺寸非常重要
現在已經不再是在