【JS】784- 14 個 JS 優化建議

JavaScript 已經成爲當下最流行的編程語言之一。根據 W3Tech,全世界幾乎 96% 的網站都在使用它。關於網站,你須要知道的最關鍵的一點是,你沒法控制訪問你網站的用戶的硬件設備規格。訪問你的網站的終端用戶也許使用了高端或低端的設備,用着好的或差的網絡鏈接。這意味着你必須確保你的網站是儘量優化的,你可以知足任何用戶的要求。
javascript

這裏有一些技巧,能夠幫助你更好地優化 JavaScript 代碼,從而提升性能。前端

順便提一下,爲了共享和複用 JS 組件,須要在高質量代碼(須要花時間)和合理交付時間之間保持正確的平衡。你可使用流行的工具例如 Bit (Github),去共享組件(vanilla JS, TS, React, Vue 等)到 Bit 的 component hub,而不浪費太多時間。java

1. 刪除不使用的代碼和功能

程序包含越多的代碼,給客戶端傳遞的數據就越多。瀏覽器也須要更多的時間去解析和編譯代碼。webpack

有時,代碼裏也許會包含徹底未使用到的功能,最好只將這些額外的代碼保留在開發環境中,而且不要把它們留到生產環境中,由於無用的代碼可能會增長客戶端瀏覽器的負擔。c++

常常問本身那個函數、特性或代碼是不是必需的。git

你能夠手動的刪掉無用的代碼,也能夠用工具 Uglify 或 谷歌開發的 Closure Compiler 幫你刪。你甚至可使用一種叫作 tree shaking 的技術來刪除程序中未使用的代碼。例如打包工具 Webpack 就提供了它。你能夠在 這裏 瞭解更多關於 tree shaking 信息。還有,若是你想刪掉未使用的 npm 包,你能夠輸入命令 npm prune 。閱讀 NPM 文檔 瞭解更多。github

2. 儘量緩存

緩存經過減小等待時間和網絡請求提升了網站的速度和性能,所以減小了展現資源的時間。能夠藉助於 緩存 API 或 HTTP 緩存 實現它。你也許好奇當內容改變時發生了什麼。上述緩存機制可以在知足某些條件(如發佈新內容)時處理和從新生成緩存。web

3. 避免內存泄漏

做爲一種高級語言,JS 負責幾個低級別的管理,好比內存管理。對於大多數編程語言來講,垃圾回收是一個常見的過程。通俗地說,垃圾回收就是簡單地收集和釋放,那些已經分配給對象,但目前又不被程序任一部分使用的內存。在像 C 這樣的編程語言中,開發者必須使用 malloc()dealloc() 函數來處理內存分配和回收。算法

儘管垃圾回收是 JavaScript 自動執行的,但在某些狀況下,它可能並不完美。在 JavaScript ES6 中,Map 和 Set 與它們的「weaker」兄弟元素一塊兒被引入。「weaker」對應着 WeakMap 和 WeakSet,持有的是每一個鍵對象的「弱引用」。它們容許對未引用的值進行垃圾收集,從而防止內存泄漏。瞭解更多關於 WeakMaps 的信息。npm

4. 儘早跳出循環 Try to Break Out of Loops Early

執行循環在代碼量大的循環中確定會消耗大量寶貴的時間,這就是爲何要儘早打破循環的緣由。你可使用 break 關鍵字和continue 關鍵字跳出循環。編寫最有效的代碼是開發者們的責任。

在下面的例子中,若是你不在循環中使用 break ,你的代碼將運行循環 1000000000 次,顯然是超出負荷的。

let arr = new Array(1000000000).fill('----');
arr[970] = 'found';
for (let i = 0; i < arr.length; i++) {
  if (arr[i] === 'found') {
        console.log("Found");
        break;
    }
}

在下面的例子中,當不知足條件時若是你不使用 continue,那麼將執行函數 1000000000 次。而咱們只處理了位於偶數位置的數組元素,就將循環執行減小了近一半。

let arr = new Array(1000000000).fill('----');
arr[970] = 'found';
for (let i = 0; i < arr.length; i++) {
  if(i%2!=0){
        continue;
    };
    process(arr[i]);
}

你能夠在 這裏 瞭解更多關於循環和性能。

5. 最小化變量的計算次數

要減小計算變量的次數,可使用閉包。JavaScript 中的閉包容許你從內部函數訪問外部函數做用域。每次建立一個函數時都會建立閉包——但不調用。內部函數能夠訪問外部做用域的變量,即便外部函數已經調用結束。

讓咱們看兩個例子,看看這是怎麼回事。這些例子的靈感來自 Bret 的博客。

function findCustomerCity(name{
  const texasCustomers = ['John''Ludwig''Kate']; 
  const californiaCustomers = ['Wade''Lucie','Kylie'];
  
  return texasCustomers.includes(name) ? 'Texas' : 
    californiaCustomers.includes(name) ? 'California' : 'Unknown';
};

若是咱們屢次調用上述函數,每次都會建立一個新對象。對於每一個調用,不會將內存從新分配給變量 texasCustometrscaliforniaCustomers

經過使用帶有閉包的解決方案,咱們只能實例化變量一次。讓咱們看看下面的例子。

function findCustomerCity({
  const texasCustomers = ['John''Ludwig''Kate']; 
  const californiaCustomers = ['Wade''Lucie','Kylie'];
  
  return name => texasCustomers.includes(name) ? 'Texas' : 
    californiaCustomers.includes(name) ? 'California' : 'Unknown';
};

let cityOfCustomer = findCustomerCity();

cityOfCustomer('John');//Texas
cityOfCustomer('Wade');//California
cityOfCustomer('Max');//Unknown

上述例子中,在閉包的幫助下,返回給變量 cityOfCustomer 的內部函數能夠訪問外部函數 findCustomerCity() 的常量。而且當調用內部函數並傳參 name 時,不須要再次實例化這些常量。若是想要對閉包有更多瞭解,我建議你瀏覽Prashant的這篇博客。

6. 最小化 DOM 的訪問

與其餘 JavaScript 語句相比,訪問 DOM 要慢一些。若是你要操做 DOM,從而觸發重繪佈局,那麼操做會變得至關緩慢。

要減小訪問 DOM 元素的次數,請訪問它一次,並將其做爲局部變量使用。當需求完成時,確保經過將變量設置爲 null 來刪除該變量的值。這將防止內存泄漏,由於它容許垃圾回收。

7. 壓縮文件

經過使用諸如 Gzip 之類的壓縮方法,能夠減少 JavaScript 文件的大小。這些較小的文件將提高網站性能,由於瀏覽器只須要下載較小的資源。

這些壓縮能夠減小多達 80% 的文件大小。在這裏瞭解更多關於 壓縮:https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/optimize-encoding-and-transfer#text_compression_with_gzip


8. 縮小你的最終代碼

有些人認爲縮小和壓縮是同樣的。但卻相反,它們是不一樣的。在壓縮中,使用特殊的算法來改變輸出文件的大小。但在縮小中,須要刪除 JavaScript 文件中的註釋和額外的空格。這個過程能夠在網上找到的許多工具和軟件包的幫助下完成。縮小已經成爲頁面優化的標準實踐和前端優化的主要組成部分。

縮小能夠減小你的文件大小高達 60%。在這裏瞭解更多關於 縮小。

9. 使用節流 throttle 和防抖 debounce

經過使用這兩種技術,咱們能夠嚴格執行代碼須要處理事件的次數。

節流是指函數在指定時間內被調用的最大次數。例如,「最多每 1000 毫秒執行一次 onkeyup 事件函數」。這意味着若是你每秒輸入 20 個鍵,該事件將每秒只觸發一次。這將減小代碼的加載。

另外一方面,防抖是指函數在上次觸發後再次觸發要間隔的最短期。換句話說,「僅當通過 600 毫秒而沒有調用該函數時才執行該函數」。這將意味着,你的函數將不會被調用,直到 600 毫秒後,最後一次執行相同的函數。要了解更多關於節流和防抖的知識,這裏有一個快速閱讀。

你能夠實現本身的防抖和節流函數,也能夠從 Lodash 和 Underscore 等庫導入它們。

10. 避免使用 delete 關鍵字

delete 關鍵字用於從對象中刪除屬性。關於這個 delete 關鍵字的性能,已經有一些爭議。你能夠在 此處 和 [此處](https://stackoverflow.com/questions/43594092/slow-delete-of-object- propertieses-in-js-in-v8/44008788) 中查看它們。這個問題有望在將來的更新中獲得解決。

As an alternative, you can simply to set the unwanted property as undefined. 另外一種選擇是,你能夠直接將將不想要的屬性設置爲 undefined

const object = {name:"Jane Doe"age:43};
object.age = undefined;

你還可使用 Map 對象,由於根據 Bret,Map 的 delete 方法被認爲更快。

11. 使用異步代碼防止線程阻塞

你應該知道 JavaScript 是同步的,也是單線程的。可是在某些狀況下,可能會花費大量的時間來執行一段代碼。在本質上同步意味着,這段代碼將阻止其餘代碼語句的運行,直到它完成執行,這會下降代碼的總體性能。

但其實,咱們能夠經過實現異步代碼來避免這種狀況。異步代碼之前是以回調的形式編寫的,可是在 ES6 中引入了一種處理異步代碼的新風格。這種新風格被稱爲 promises。你能夠在 MDN 的官方文檔 中瞭解更多關於回調和 promises 的信息。

等等…

JavaScript默認是同步的,也是單線程的

爲何在單一線程上運行,還能運行異步代碼?這是不少人感到困惑的地方。這要歸功於瀏覽器外殼下運行的 JavaScript 引擎。JavaScript 引擎是執行 JavaScript 代碼的計算機程序或解釋器。JavaScript 引擎能夠用多種語言編寫。例如,支持 Chrome 瀏覽器的 V8 引擎是用 c++ 編寫的,而支持 Firefox 瀏覽器的 SpiderMonkey 引擎是用 C 和 c++ 編寫的。

這些 JavaScript 引擎能夠在後臺處理任務。根據 Brian,調用棧識別 Web API 的函數,並將它們交給瀏覽器處理。一旦瀏覽器處理完成這些任務,它們將返回並做爲回調推到堆棧上。

你有時可能想知道,Node.js 在沒有瀏覽器幫助的狀況下是如何運行的。事實上,爲 Chrome 提供動力的 V8 引擎一樣也爲 Node.js 提供動力。下面是一篇由 Salil 撰寫的很是棒的博客文章:Node.js真的是單線程嗎,它解釋了節點生態系統上的這個過程。

12. 使用代碼分割

若是你有使用 Google Light House 的經驗,你就會熟悉一個叫作「first contentful paint」的度量。它是 Lighthouse 報告的性能部分跟蹤的六個指標之一。

First Contentful Paint(FCP)測量用戶導航到頁面後瀏覽器渲染 DOM 第一個內容所花費的時間。頁面上的圖像、非白色 <canvas> 元素和 SVG 被認爲是 DOM 內容;iframe 中的任何內容都不被包含在內。

得到更高 FCP 分數的最好方法之一是使用代碼分割。代碼分割是一種在開始時只向用戶發送必要模塊的技術。減小最初傳輸的有效內容的大小,會顯著地影響 FCP 得分。

流行的模塊打包工具(如 webpack)提供了代碼分割功能。你能夠在原生 ES 模塊的幫助下,加載各個模塊。你能夠閱讀更多關於原生 ES 模塊的 詳細信息。

13. 使用異步 async 和延遲 defer

在現代網站中,腳本比 HTML 更密集,它們的尺寸更大,消耗更多的處理時間。默認狀況下,瀏覽器必須等待腳本下載、執行,而後處理頁面的其他部分。

龐大的腳本可能會阻塞網頁的加載。爲了不這種狀況,JavaScript 提供了兩種技術,即異步和延遲。你只需將這些屬性添加到 <script> 標籤。

異步是告訴瀏覽器在不影響頁面渲染的狀況下加載腳本。換句話說,頁面不須要等待異步腳本,內容就會被處理和顯示。

延遲是在呈現完成後告訴瀏覽器加載腳本的地方。若是你同時指定了二者,async 在現代瀏覽器中優先執行,而只支持 defer 但不支持 async 的舊瀏覽器將退回到 defer

這兩個屬性能夠極大地幫助你減小頁面加載時間。強烈建議你閱讀一下 Flavio 的 JavaScript-async-defer。

14. 使用 Web Workers 在後臺運行 CPU 密集型任務

Web Workers 容許在後臺線程中運行腳本。若是你有一些高度密集的任務,你能夠將任務分配給 web workers, web workers 將運行它們而不干擾用戶界面。建立以後,web worker 能夠經過向 JavaScript 代碼指定的事件處理程序發送消息來與 JavaScript 代碼通訊。反之亦然。

要了解更多關於 web workers 的信息,建議瀏覽 MDN 文檔。


這篇文章就到這裏,歡迎在評論中留言。

快樂編碼!!


一些資源

  • Nodesource 的博客
  • Bret Cameron 的博客
  • 原文地址:14 JavaScript Code Optimization Tips for Front-End Developers
  • 原文做者:Mahdhi Rezvi
  • 譯文出自:掘金翻譯計劃
  • 本文永久連接:https://github.com/xitu/gold-miner/blob/master/article/2020/14-javascript-code-optimization-tips-for-front-end-developers.md
  • 譯者:Gesj-yean
  • 校對者:plusmultiply0, rachelcdev
 
    
    
     
     
              
     
 
    

1. JavaScript 重溫系列(22篇全)
2. ECMAScript 重溫系列(10篇全)
3. JavaScript設計模式 重溫系列(9篇全)
4.  正則 / 框架 / 算法等 重溫系列(16篇全)
5.  Webpack4 入門(上) ||  Webpack4 入門(下)
6.  MobX 入門(上)  ||   MobX 入門(下)
7. 8 0+篇原創系列彙總

回覆「加羣」與大佬們一塊兒交流學習~

點擊「閱讀原文」查看 80+ 篇原創文章

本文分享自微信公衆號 - 前端自習課(FE-study)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索