JavaScript 性能優化技巧分享

JavaScript 做爲當前最爲常見的直譯式腳本語言,已經普遍應用於 Web 應用開發中。爲了提升Web應用的性能,從 JavaScript 的性能優化方向入手,會是一個很好的選擇。javascript

本文從加載、上下文、解析、編譯、執行和捆綁等多個方面來說解 JavaScript 的性能優化技巧,以便讓更多的前端開發人員掌握這方面知識。html

什麼是高性能的 JavaScript 代碼?

儘管目前沒有高性能代碼的絕對定義,但卻存在一個以用戶爲中心的性能模型,能夠用做參考:RAIL模型前端

  • 響應

若是你的應用程序能在100毫秒內響應用戶的操做,那麼用戶會認爲該響應爲即時的。這適用於可點擊的元素,不適用於滾動或拖動操做。java

  • 動畫

在60Hz的顯示器上,咱們但願動畫和滾動時每秒有60幀,這種狀況下每幀大約爲16ms。在這16ms的時間內,實際上只有8-10ms來完成全部工做,其他時間則由瀏覽器的內部和其它差別佔據。react

  • 空閒工做

若是你有一個耗時好久,須要持續運行的任務時,請確保把它分紅很小的塊,以便容許主線程對用戶的輸入操做作出反應。不該該出現一個任務延遲超過50ms的用戶輸入。webpack

  • 加載

頁面加載應該在1000毫秒內完成。在移動設備上,這是一個很難達到的目標,由於它涉及到頁面的互動,而不只僅是在屏幕上渲染和滾動。git

 

現代加載最佳實踐(Chrome Dev Summit 2017)github

 讓咱們來看看一些統計數據web

  • 若是移動網站的加載時間超過三秒,則會有53%的用戶放棄訪問npm

  • 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 轉換等技術。

 

捆綁尺寸很是重要

如今已經再也不是在 </body> 結束標籤以前包含有多個 <script> 的時代了。如今,能夠在 npm 上找到各式各樣的工具包,而且能夠將這些工具包和 Webpack 捆綁在一個單個的 1MB 大小的 JavaScript 文件中,在完成數據計劃時,提醒用戶的瀏覽器進行爬取。

這樣可使用更少許的 JavaScript,這也意味着你的項目可能再也不須要整個Lodash庫。若是必須使用 JavaScript 庫,也能夠考慮使用 React 之外的東西,好比 Preact 或者 HyperHTML,它們只是 React 的1/20大小。

Webpack 3 有着神奇的功能,被稱做代碼分割動態導入。它不會將全部 JavaScript 模塊捆綁到一個 app.js 整包中,而是使用 import( ) 語法自動分割代碼而且進行異步加載。

你不須要使用框架、組件和客戶端路由,就能得到這些好處。你只須要簡單地在主 JavaScript 文件中寫入如下內容:

if (document.querySelector('.mega-widget')) {
    import('./mega-widget');
}

若是你的應用程序須要在頁面上用到這個小部件,它將動態加載所需的支持代碼。

另外,Webpack 須要運行時間來工做,並將其注入到它生成的全部 .js 文件中。若是使用該 commonChunks 插件,則可使用如下內容將運行時抽取到 Chunk 中:

new webpack.optimize.CommonsChunkPlugin({
  name: 'runtime',
}),

確保 Webpack 在主 JavaScript 包以前已完成加載,那麼全部其它 chunk 中的運行時間會剝離到各自的文件中,這種狀況也被成爲 runtime.js。例如:

<script src="runtime.js">
<script src="main-bundle.js">

而後是編譯代碼和 polyfills 的部分。若是你正在編寫現代 JavaScript 代碼(ES6 +),則可使用 Babel 將其轉換爲 ES5 兼容的代碼。與原生 ES6+ 代碼相比,編譯不只增長了文件的大小,還增長了複雜性,而且常常會出現性能降低的狀況。

除此以外,你還極可能使用 babel-polyfill 軟件包和 whatwg-fetch,來修復舊版本瀏覽器中的缺失功能。所以若是你正在編寫 async/await,你還須要使用包 regenerator-runtime 的生成器來進行編譯。

問題是,你爲 JavaScript 軟件包添加了近 100KB 的內容,這不只是一個巨大的文件,並且預示着巨大的解析和執行花費,以便可以支持舊版本的瀏覽器。

一種方法是建立兩個獨立的 bundle,並根據實際條件來加載它們。Babel 轉換編譯器在 babel-preset-env 的幫助下,會使同時面臨新舊兩種瀏覽器的狀況更加容易處理。

一個並不規範但行之有效的方法,是將如下內容放在一個內聯腳本中:

(function() {  try {    new Function('async () => {}')();
  } catch (error) {    // create script tag pointing to legacy-bundle.js;
    return;
  }  // create script tag pointing to modern-bundle.js;;})();

若是瀏覽器沒法識別 async 函數,則會被認爲是舊版本的瀏覽器,此時就會用到 polyfill 包。若是能識別,用戶則將獲得現代瀏覽器的處理。

JavaScript 開發工具推薦

SpreadJS 純前端表格控件是基於 HTML5 的 JavaScript 電子表格和網格功能控件,提供了完備的公式引擎、排序、過濾、輸入控件、數據可視化、Excel 導入/導出等功能,適用於 .NET、Java 和移動端等各平臺在線編輯類 Excel 功能的表格程序開發。

結論

想要提升網站的運行速度,就須要確保網站能快速的加載 JavaScript 文件,以實現快速的互動。你的 JavaScript 代碼應該被分紅更小的、可管理的 bundle,同時儘量地進行異步加載。在服務器端,請確保啓用了 HTTP 2.0,以便實現更快的並行傳輸和 gzip/Brotli 壓縮,從而大大減小了 JavaScript 的傳輸大小。

原文連接:https://www.sitepoint.com/javascript-performance-optimization-tips-an-overview/

轉載請註明出自:葡萄城控件

相關文章
相關標籤/搜索