日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

14個(gè) JavaScript 代碼優(yōu)化技巧

 

作者 | Mahdhi Rezvi

譯者 | 王強(qiáng)

策劃 | 李俊辰

轉(zhuǎn)發(fā)鏈接:https://mp.weixin.qq.com/s/veJ6mhxd5XwVG4OF7i0VYQ

前言

這篇文章列舉了一些技巧,可幫助你寫(xiě)出更好的 JAVAScript 代碼,從而提高性能。

本文最初發(fā)布于 Medium 網(wǎng)站,經(jīng)原作者授權(quán)由 InfoQ 中文站翻譯并分享。

JavaScript 已經(jīng)成為有史以來(lái)最受歡迎的編程語(yǔ)言之一。從 W3Tech 的數(shù)據(jù)來(lái)看,全世界將近 96%的網(wǎng)站都在使用它。關(guān)于 Web 有一個(gè)關(guān)鍵的事實(shí)是,你無(wú)法控制訪問(wèn)網(wǎng)站的用戶所用設(shè)備。當(dāng)用戶訪問(wèn)你的網(wǎng)站時(shí),使用的可能是高端設(shè)備也可能是低端設(shè)備,網(wǎng)絡(luò)連接條件也有好有差。這意味著你必須盡可能優(yōu)化自己的網(wǎng)站,以滿足任何用戶的需求。

附帶提一下,請(qǐng)共享和重用你的 JS 組件,以在高質(zhì)量代碼(寫(xiě)起來(lái)需要花費(fèi)時(shí)間)和合理的交付時(shí)間之間保持適當(dāng)?shù)钠胶狻D憧梢允褂?Bit 等流行工具將任何項(xiàng)目中的組件(普通 JS、TS、React、Vue 等)共享到 Bit 的組件中心,用不了多大功夫。

1、刪除未使用的代碼和功能

你的應(yīng)用程序包含的代碼越多,就需要將更多的數(shù)據(jù)傳輸?shù)娇蛻舳恕g覽器也需要更多時(shí)間來(lái)分析和解釋代碼。

有時(shí),你可能打包了很多根本用不到的功能。最好只在開(kāi)發(fā)環(huán)境中保留這些額外的代碼,而不要將其推送到生產(chǎn)環(huán)境中,以免給客戶端的瀏覽器增加負(fù)擔(dān)。

要不斷問(wèn)自己,某個(gè)功能或代碼段是否是必要的。

你可以手動(dòng)移除未使用的代碼,也可以使用 Uglify 或谷歌的 Closure Compiler 之類(lèi)的工具刪除它們。你還可以使用一種被稱為搖樹(shù)優(yōu)化的技術(shù)從應(yīng)用程序中刪除未使用的代碼。Webpack 這類(lèi)打包軟件提供了這種技術(shù),詳情可以參考這里:

https://www.infoq.cn/article/dcKcJiT8aeEBNZbdotFF

如果要?jiǎng)h除未使用的 npm 軟件包,可以使用命令 npm prune,詳細(xì)信息參考 NPM 文檔。

https://docs.npmjs.com/cli-commands/prune.html

2、盡可能的緩存

緩存可以減少延遲和網(wǎng)絡(luò)流量,從而減少了顯示資源表示所需的時(shí)間,以提高網(wǎng)站的速度和性能。緩存可以借助 Cache API 或 HTTP caching 來(lái)實(shí)現(xiàn)。你可能想知道內(nèi)容更改時(shí)會(huì)發(fā)生什么。當(dāng)滿足某些條件(例如發(fā)布新內(nèi)容)時(shí),上述緩存機(jī)制能夠處理和重新生成緩存。

3、避免內(nèi)存泄漏

作為一種高級(jí)語(yǔ)言,JS 會(huì)負(fù)責(zé)一些底層管理工作,例如內(nèi)存管理。垃圾回收是大多數(shù)編程語(yǔ)言共有的過(guò)程。用外行術(shù)語(yǔ)來(lái)說(shuō),垃圾收集就是收集并釋放已分配給對(duì)象,但目前尚未在程序的任何部分中使用的內(nèi)存。在 C 這樣的編程語(yǔ)言中,開(kāi)發(fā)人員必須使用 malloc() 和 dealloc() 函數(shù)來(lái)處理內(nèi)存分配和釋放操作。

雖然在 JavaScript 中垃圾回收是自動(dòng)執(zhí)行的,但在某些情況下它也不是完美的。在 JavaScript ES6 中,引入了 Map 和 Set 及其“weaker”的同級(jí)對(duì)象。被稱為 WeakMap 和 WeakSet 的“較弱”對(duì)應(yīng)項(xiàng)持有對(duì)對(duì)象的“弱”引用。它們使未引用的值能夠被垃圾回收,從而防止內(nèi)存泄漏。你可以在此處了解有關(guān) WeakMaps 的更多信息:

https://blog.bitsrc.io/understanding-weakmaps-in-javascript-6e323d9eec81

4、盡早打破循環(huán)

超大循環(huán)肯定會(huì)耗費(fèi)很多的時(shí)間,所以你應(yīng)該盡早打破這些超大循環(huán)。你可以用 break 關(guān)鍵字和 continue 關(guān)鍵字來(lái)做這件事,從而編寫(xiě)更高效的代碼。

在下面的示例中,如果你沒(méi)有從循環(huán)中 break,則你的代碼將循環(huán)運(yùn)行 1000000000 (10億)次,顯然會(huì)過(guò)載的。

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;
    }
}

在下面的示例中,如果你在循環(huán)不符合你的條件時(shí)沒(méi)有 continue,則你仍將運(yùn)行該函數(shù) 1000000000 次。我們僅在數(shù)組元素處于偶數(shù)位置時(shí)處理它。這將循環(huán)執(zhí)行減少了近一半。

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]);
}

你可以在此處詳細(xì)了解循環(huán)和性能的關(guān)系:

https://www.oreilly.com/library/view/high-performance-javascript/9781449382308/ch04.html

5、最小化變量計(jì)算的次數(shù)

為了減少計(jì)算變量的次數(shù),可以使用閉包。通俗來(lái)說(shuō),JavaScript 中的閉包使你可以從內(nèi)部函數(shù)訪問(wèn)外部函數(shù)作用域。每次創(chuàng)建函數(shù)(不調(diào)用)時(shí)都會(huì)創(chuàng)建閉包。內(nèi)部函數(shù)將有權(quán)訪問(wèn)外部作用域的變量,即使在返回外部函數(shù)之后也是如此。

我們來(lái)看兩個(gè)例子。這些示例均來(lái)自 Bret 的博客。

function findCustomerCity(name) {
  const texasCustomers = ['John', 'Ludwig', 'Kate'];
  const californiaCustomers = ['Wade', 'Lucie','Kylie'];

  return texasCustomers.includes(name) ? 'Texas' :
    californiaCustomers.includes(name) ? 'California' : 'Unknown';
};

如果你多次調(diào)用上面的函數(shù),那么每次都會(huì)創(chuàng)建一個(gè)新對(duì)象。每次調(diào)用時(shí),變量 texasCustomers 和 californiaCustomers 都會(huì)導(dǎo)致不必要的內(nèi)存重分配。

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 的內(nèi)部函數(shù)可以訪問(wèn)外部函數(shù) findCustomerCity() 的常量。而且,每當(dāng)以傳遞的名稱作為參數(shù)調(diào)用內(nèi)部函數(shù)時(shí),都無(wú)需再次實(shí)例化常量。要了解關(guān)于閉包的更多信息,建議你閱讀 Prashant 的博客文章:

https://medium.com/@prashantramnyc/javascript-closures-simplified-d0d23fa06ba4

6、盡量減少 DOM 訪問(wèn)

與其他 JavaScript 語(yǔ)句相比,訪問(wèn) DOM 的速度很慢。如果你對(duì) DOM 進(jìn)行更改,觸發(fā)了布局的重新繪制,那么就得等好一陣子了。

為了減少訪問(wèn) DOM 元素的次數(shù),請(qǐng)先訪問(wèn)一次,然后將其用作局部變量。完成需求后,請(qǐng)一定將其設(shè)置為 null 來(lái)移除該變量的值。這將防止內(nèi)存泄漏,因?yàn)檫@會(huì)觸發(fā)垃圾回收過(guò)程。

7、壓縮文件

通過(guò)壓縮方法(例如 Gzip)可以減小 JavaScript 文件的大小。較小的文件會(huì)提升你的網(wǎng)站性能,因?yàn)闉g覽器只需下載較小的資產(chǎn)即可。

這類(lèi)壓縮手段最多可以減少 80%的文件大小。在此處閱讀有關(guān)壓縮的更多信息:

https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/optimize-encoding-and-transfer#text_compression_with_gzip

8、縮小最終代碼

有人認(rèn)為縮小和壓縮是相同的,其實(shí)不然。在壓縮中,我們使用特殊算法來(lái)改變文件的輸出大小;在縮小時(shí),我們需要?jiǎng)h除 JavaScript 文件中的注釋和多余的空格。可以在網(wǎng)上找到許多工具和軟件包來(lái)幫助完成這一過(guò)程。縮小已成為頁(yè)面優(yōu)化的標(biāo)準(zhǔn)做法,也是前端優(yōu)化的主要步驟之一。

縮小可以讓文件大小最多減少 60%。你可以在此處閱讀有關(guān)縮小的更多信息:

https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/optimize-encoding-and-transfer#minification_preprocessing_context-specific_optimizations

9、使用 Throttle 和 Debounce

我們可以使用 Throttle(節(jié)流)和 Debounce(防抖)這兩種技術(shù)來(lái)嚴(yán)格控制代碼需要處理事件的次數(shù)。

節(jié)流是指定函數(shù)可以超時(shí)的最大次數(shù)。例如,“每 1000 毫秒最多執(zhí)行一次 onkeyup 事件函數(shù)”。也就是說(shuō)哪怕你每秒敲 20 個(gè)鍵,該事件每秒也只會(huì)觸發(fā)一次。這將減少代碼的負(fù)擔(dān)。

另一方面,防抖是指定自上次執(zhí)行相同函數(shù)以來(lái)再次運(yùn)行該函數(shù)的最短持續(xù)時(shí)間。換句話說(shuō),“上次調(diào)用函數(shù)后果最少 600 毫秒才執(zhí)行此函數(shù)”。要了解有關(guān)節(jié)流和防抖的更多信息,這里有一篇快速入門(mén):

https://css-tricks.com/the-difference-between-throttling-and-debouncing/

你可以實(shí)現(xiàn)自己的防抖和節(jié)流函數(shù),也可以從 Lodash 和 Underscore 之類(lèi)的庫(kù)中導(dǎo)入它們。

10、避免使用 Delete 關(guān)鍵字

delete 關(guān)鍵字用于從對(duì)象中刪除屬性。這個(gè)關(guān)鍵字的性能表現(xiàn)不怎么好,預(yù)計(jì)它將在未來(lái)的更新中修復(fù)。

或者,你可以簡(jiǎn)單地將不需要的屬性設(shè)置為 undefined。

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

你還可以使用 Map 對(duì)象,Bret 認(rèn)為它的 delete 方法會(huì)更快。

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

你應(yīng)該知道 JavaScript 默認(rèn)情況下是同步的和單線程的。但是在某些情況下,你的代碼需要很大的計(jì)算量。代碼本質(zhì)上是同步的,意味著一段代碼運(yùn)行時(shí)將阻止其他代碼語(yǔ)句運(yùn)行,直到前者完成執(zhí)行為止。這會(huì)降低整體性能。

但是我們可以通過(guò)異步代碼來(lái)避免這種情況。異步代碼以前以回調(diào)的形式編寫(xiě),但是 ES6 引入了一種處理異步代碼的新樣式。這種新樣式被稱為 Promise。你可以在 MDN 的官方文檔中了解有關(guān)回調(diào)和 Promise 的更多信息。

https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Introducing

可是等等……

JavaScript 默認(rèn)情況下是同步的,并且也是單線程的。

如何在單個(gè)線程上運(yùn)行異步代碼呢?這是很多人感到困惑的地方。做到這一點(diǎn),主要依賴運(yùn)行在瀏覽器后臺(tái)的 JavaScript 引擎。JavaScript 引擎是執(zhí)行 JavaScript 代碼的計(jì)算機(jī)程序或解釋器。JavaScript 引擎可以用多種語(yǔ)言編寫(xiě)。例如,支持 Chrome 瀏覽器的 V8 引擎使用 C++ 編寫(xiě)的,而支持 Firefox 瀏覽器的 SpiderMonkey 引擎使用 C 和 C++ 編寫(xiě)的。

這些 JavaScript 引擎可以在后臺(tái)處理任務(wù)。根據(jù) Brian 的說(shuō)法,調(diào)用棧可以識(shí)別 Web API 的函數(shù),并將其交給瀏覽器處理。瀏覽器完成這些任務(wù)后,它們將返回并作為回調(diào)被推上堆棧。

你可能想知道 Node.js 是怎么做這些工作的,畢竟它沒(méi)有瀏覽器的幫助。實(shí)際上,支持 Chrome 的那個(gè) V8 引擎也是 Node.js 背后的支撐。這里有 Salil 的一篇很棒的博客文章,解釋了 Node 生態(tài)系統(tǒng)中的這一過(guò)程。

https://medium.com/better-programming/is-node-js-really-single-threaded-7ea59bcc8d64

12、使用代碼拆分

如果你有使用 Google Light House 的經(jīng)驗(yàn),肯定會(huì)熟悉一種稱為“first contentful paint”的指標(biāo)。它是 Lighthouse 報(bào)告的 Performance 部分中跟蹤的六個(gè)指標(biāo)之一。

First Contentful Paint(FCP)衡量用戶轉(zhuǎn)到你的頁(yè)面后瀏覽器渲染第一段 DOM 內(nèi)容所花費(fèi)的時(shí)間。頁(yè)面上的圖像、非白色<canvas>元素和 SVG 被視為 DOM 內(nèi)容;iframe 內(nèi)部不包含任何內(nèi)容。

獲得更高的 FCP 分?jǐn)?shù)的最佳方法之一是使用代碼拆分。代碼拆分是一種在傳輸開(kāi)始時(shí)僅將必要的模塊發(fā)送給用戶的技術(shù)。通過(guò)減小最初發(fā)送的載荷大小,這將極大地影響 FCP 分?jǐn)?shù)。

流行的模塊打包器(例如 webpack)可為你提供代碼拆分功能。你還可以利用原生 ES 模塊來(lái)單獨(dú)加載各個(gè)模塊。你可以在此處詳細(xì)了解有關(guān)原生 ES 模塊的信息。

https://blog.bitsrc.io/understanding-es-modules-in-javascript-a28fec420f73

13、使用 async 和 defer

在現(xiàn)代網(wǎng)站中,腳本比 HTML 更為密集,其大小更大且消耗更多的處理時(shí)間。默認(rèn)情況下,瀏覽器必須等待腳本下載和執(zhí)行完畢后,再處理頁(yè)面的其余部分。

于是笨重的腳本可能會(huì)阻止網(wǎng)頁(yè)的加載。為了避免這種情況,JavaScript 為我們提供了兩種分別稱為 async 和 defer 的技術(shù)。你只需將這些屬性添加到<script>標(biāo)記中即可。

Async 會(huì)讓瀏覽器在不影響渲染的情況下加載腳本。換句話說(shuō),頁(yè)面不會(huì)等待 async 腳本,而是先處理和顯示內(nèi)容。

Defer 是讓瀏覽器在渲染完成后加載腳本。如果同時(shí)指定它們兩者,則 async 在現(xiàn)代瀏覽器上更優(yōu)先,而支持 defer 但不支持 async 的老式瀏覽器將回退為 defer。

這兩個(gè)屬性可以幫助你大幅減少頁(yè)面加載時(shí)間。我強(qiáng)烈建議你閱讀 Flavio 的這篇博客文章。

https://flaviocopes.com/javascript-async-defer/

14、在后臺(tái)運(yùn)行 CPU 密集型任務(wù)

可以使用 Web Worker 在后臺(tái)線程中運(yùn)行腳本。如果你有一些高強(qiáng)度的任務(wù),可以將它們分配給 Web Worker,這些 WebWorker 可以在不干擾用戶界面的情況下運(yùn)行它們。創(chuàng)建后,Web Worker 可以將消息發(fā)布到該代碼指定的事件處理程序來(lái)與 JavaScript 代碼通信,反之亦然。

作者 | Mahdhi Rezvi

譯者 | 王強(qiáng)

策劃 | 李俊辰

轉(zhuǎn)發(fā)鏈接:https://mp.weixin.qq.com/s/veJ6mhxd5XwVG4OF7i0VYQ

分享到:
標(biāo)簽:優(yōu)化 代碼 avaScript
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定