本文探討了在瞬息萬變的 JavaScript 生態系統中,如何優化 JavaScript 性能的諸多方面。我們將遵循“工具而非規則”的原則,盡量避免使用過多的 JavaScript 行話。由於篇幅有限,無法涵蓋 JavaScript 性能優化的所有方面,請務必閱讀參考鏈接並自行深入研究。
在深入探討細節之前,讓我們先從更宏觀的角度來理解這個問題:什麼是高性能 JavaScript,它如何與更廣泛的 Web 性能指標相適應?
關鍵要點
背景設置
首先,我們需要明確一點:如果您只在台式機上進行測試,那麼您就排除了超過 50% 的用戶。
隨著新興市場用戶主要通過價格低於 100 美元的 Android 設備訪問互聯網,這一趨勢只會繼續發展。台式機作為訪問互聯網的主要設備的時代已經結束,下一批十億互聯網用戶將主要通過移動設備訪問您的網站。
在 Chrome DevTools 的設備模式下進行測試並不能替代在真實設備上進行測試。使用 CPU 和網絡限流有所幫助,但它本質上是不同的。請在真實設備上進行測試。
即使您正在在真實的移動設備上進行測試,您可能也在使用您全新的 600 美元旗艦手機進行測試。問題是,這並不是您的用戶所擁有的設備。中位數設備類似於 Moto G1——這是一款內存小於 1GB、CPU 和 GPU 非常弱的設備。
讓我們看看它在解析平均 JS 包時的表現如何。
Addy Osmani:JS 解析和評估的平均時間。
糟糕。雖然此圖像僅涵蓋 JS 的解析和編譯時間(稍後將詳細介紹),而不是整體性能,但它與整體性能密切相關,可以作為整體 JS 性能的指標。
引用 Bruce Lawson 的話:“這是萬維網,而不是富裕的西方網絡”。因此,您的 Web 性能目標是速度比您的 MacBook 或 iPhone 慢約 25 倍的設備。好好想想這一點。但情況更糟。讓我們看看我們的實際目標是什麼。
什麼是高性能 JS 代碼?
既然我們知道了目標平台,我們就可以回答下一個問題:什麼是高性能 JS 代碼?
雖然沒有絕對的分類來定義高性能代碼,但我們確實有一個以用戶為中心的性能模型可以用作參考:RAIL 模型。
Sam Saccone:性能規劃:PRPL
如果您的應用在 100 毫秒內響應用戶操作,用戶會認為響應是即時的。這適用於可點擊的元素,但不適用於滾動或拖動。
在 60Hz 顯示器上,我們希望在動畫和滾動時達到每秒 60 幀的恆定幀率。這意味著每幀大約有 16 毫秒的時間。在這 16 毫秒的預算中,您實際上只有 8-10 毫秒的時間來完成所有工作,其餘時間被瀏覽器內部機制和其他差異佔用。
如果您有一個昂貴且持續運行的任務,請確保將其分割成更小的塊,以便主線程能夠響應用戶輸入。您不應該有一個任務會將用戶輸入延遲超過 50 毫秒。
您應該將頁面加載時間控制在 1000 毫秒以內。超過這個時間,您的用戶就會開始感到不耐煩。對於頁面具有交互性而言,這是一個相當難以實現的目標,而不僅僅是將其繪製在屏幕上並可滾動。實際上,時間更短:
Fast By Default:現代加載最佳實踐(2017 年 Chrome Dev 峰會)
實際上,目標是 5 秒的交互時間。這是 Chrome 在其 Lighthouse 審核中使用的指標。
既然我們知道了指標,讓我們來看一些統計數據:
以及 Addy Osmani 提供的更多信息:
感覺夠沮喪了嗎?很好。讓我們開始工作,修復 Web。 ✊
上下文至關重要
您可能已經註意到,主要瓶頸是加載網站所需的時間。具體來說,是 JavaScript 下載、解析、編譯和執行時間。除了加載更少的 JavaScript 代碼並更智能地加載之外,別無他法。
但是,除了啟動網站之外,您的代碼實際執行的工作呢?那裡一定有一些性能提升,對吧?
在深入優化代碼之前,請考慮您正在構建的內容。您是在構建框架還是 VDOM 庫?您的代碼是否需要每秒執行數千次操作?您是否正在為處理用戶輸入和/或動畫編寫一個時間關鍵型庫?如果不是,您可能需要將時間和精力轉移到更有效的地方。
這並不是說編寫高性能代碼不重要,而是它通常在整體情況中幾乎沒有影響,尤其是在談論微優化時。因此,在您開始在 Stack Overflow 上就 .map 與 .forEach 與 for 循環進行爭論,並比較 JSperf.com 上的結果之前,請確保您看到了森林,而不僅僅是樹木。在紙面上,50k ops/s 可能聽起來比 1k ops/s 好 50 倍,但在大多數情況下,它不會產生任何區別。
解析、編譯和執行
從根本上說,大多數非高性能 JS 的問題不是運行代碼本身,而是在代碼開始執行之前必須執行的所有步驟。
我們在這裡談論的是抽象級別。您計算機中的 CPU 運行機器碼。您計算機上運行的大部分代碼都採用編譯後的二進制格式。 (考慮到當今所有的Electron 應用程序,我說的是代碼而不是程序。)這意味著,除了所有操作系統級別的抽象之外,它都在您的硬件上原生運行,無需任何準備工作。
JavaScript 沒有預編譯。它(通過相對較慢的網絡)以可讀代碼的形式到達您的瀏覽器中,就所有意圖和目的而言,它是您的 JS 程序的“操作系統”。
該代碼首先需要進行解析——也就是說,讀取並轉換為可供計算機索引的結構,以便用於編譯。然後將其編譯成字節碼,最後編譯成機器碼,然後才能由您的設備/瀏覽器執行。
另一個非常重要的事情需要提到的是,JavaScript 是單線程的,並且在瀏覽器的主線程上運行。這意味著一次只能運行一個進程。如果您的 DevTools 性能時間軸充滿了黃色峰值,使您的 CPU 運行到 100%,您將遇到長時間/丟幀、卡頓滾動以及其他各種討厭的事情。
Paul Lewis:當一切都很重要時,什麼都不重要! 。
因此,在您的 JS 開始工作之前,需要完成所有這些工作。在 Chrome 的 V8 引擎中,解析和編譯最多佔 JS 執行總時間的 50%。
Addy Osmani:JavaScript 啟動性能。
您應該從本節中記住兩件事:
有一些方法可以減輕這種情況,例如使用服務工作線程在後台和另一個線程上執行作業,使用 asm.js 編寫更容易編譯成機器指令的代碼,但這又是另一個主題。
但是,您可以做的是避免為所有內容都使用 JS 動畫框架,並了解觸發繪製和佈局的內容。僅當絕對無法使用常規 CSS 過渡和動畫來實現動畫時,才使用這些庫。
即使它們可能使用 CSS 過渡、合成屬性和 requestAnimationFrame(),它們仍在 JS 中、在主線程上運行。它們基本上只是每 16 毫秒都用內聯樣式來敲打您的 DOM,因為它們幾乎沒有其他事情可做。為了保持動畫流暢,您需要確保所有 JS 都能在每幀 8 毫秒內完成執行。
另一方面,CSS 動畫和過渡在主線程之外運行——如果高效地實現,則在 GPU 上運行,而不會導致重新佈局/重新繪製。
考慮到大多數動畫是在加載或用戶交互期間運行的,這可以為您的 Web 應用提供急需的喘息空間。
Web Animations API 是一個即將推出的功能集,它允許您在主線程之外執行高性能 JS 動畫,但目前,請堅持使用 CSS 過渡和 FLIP 等技術。
包大小至關重要
如今,一切都是關於包的。 Bower 和在結束
以上是JavaScript性能優化提示:概述的詳細內容。更多資訊請關注PHP中文網其他相關文章!