首頁 >web前端 >js教程 >在JavaScript中詳細解讀效能優化

在JavaScript中詳細解讀效能優化

亚连
亚连原創
2018-06-21 16:10:081359瀏覽

下面我就為大家分享一篇基於JavaScript 效能優化技巧心得,具有很好的參考價值,希望對大家有幫助。一起跟著小編過來看看吧

JavaScript 作為目前最常見的直譯式腳本語言,已經廣泛應用於 Web 應用開發中。為了提升Web應用的效能,從 JavaScript 的效能優化方向入手,會是很好的選擇。

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

什麼是高效能的 JavaScript 程式碼?

儘管目前沒有高效能程式碼的絕對定義,但卻存在一個以使用者為中心的效能模型,可以用作參考:RAIL模型。

回應

如果你的應用程式能在100毫秒內回應使用者的操作,那麼使用者會認為該回應為即時的。這適用於可點擊的元素,不適用於捲動或拖曳操作。

動畫

在60Hz的顯示器上,我們希望動畫和滾動時每秒有60幀,這種情況下每幀大約為16ms。在這16ms的時間內,實際上只有8-10ms來完成所有工作,其餘時間則由瀏覽器的內部和其它差異佔據。

空閒工作

如果你有一個耗時很久,需要持續運行的任務時,請確保把它分成很小的區塊,以便允許主執行緒對使用者的輸入操作做出反應。不應該出現一個任務延遲超過50ms的使用者輸入。

載入

頁面載入應該在1000毫秒內完成。在行動裝置上,這是一個很難達到的目標,因為它涉及頁面的互動,而不僅僅是在螢幕上渲染和滾動。

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

如果行動網站的載入時間超過三秒,則會有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 轉換等技術。

捆綁尺寸非常重要

現在已經不再是在36cc49f0c466276486e50c850b7e4956 結束標籤之前包含有多個3f1c4e4b6b16bbbd69b2ee476dc4f83a的時代了。現在,可以在 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(&#39;async () => {}&#39;)();
 } catch (error) {
 // create script tag pointing to legacy-bundle.js;
 return;
 }
 // create script tag pointing to modern-bundle.js;;
})();

如果浏览器无法识别 async 函数,则会被认为是旧版本的浏览器,此时就会用到 polyfill 包。如果能识别,用户则将得到现代浏览器的处理。

结论

想要提高网站的运行速度,就需要确保网站能快速的加载 JavaScript 文件,以实现快速的互动。你的 JavaScript 代码应该被分成更小的、可管理的 bundle,同时尽可能地进行异步加载。在服务器端,请确保启用了 HTTP 2.0,以便实现更快的并行传输和 gzip/Brotli 压缩,从而大大减少了 JavaScript 的传输大小。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

使用JQUERY如何实现多个AJAX请求

使用js如何实现焦点图效果

在微信小程序中如何实现图片懒加载

以上是在JavaScript中詳細解讀效能優化的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn