說道JavaScript的代碼優(yōu)化,就先要做的是準(zhǔn)確的測(cè)試JavaScript的代碼執(zhí)行時(shí)間。簡(jiǎn)單來說就是采集大量的執(zhí)行樣本進(jìn)行數(shù)學(xué)統(tǒng)計(jì)和分析,這里我們使用的是benchmark.js來檢測(cè)代碼的執(zhí)行情況。
首先我們需要在項(xiàng)目中安裝依賴,代碼如下:
yarn add benchmark --save # 或者 npm i benchmark --save
然后我們寫一個(gè)測(cè)試代碼,如下所示:
const Benchmark = require('benchmark') const suite = new Benchmark.Suite() // 添加測(cè)試 suite /** * add() 方法接受兩個(gè)參數(shù),其中第一個(gè)表示測(cè)試的名稱,第二個(gè)表示測(cè)試的內(nèi)容,他是一個(gè)函數(shù)* / .add('join1000', () => { new Array(1000).join(' ') }) .add('join10000', () => { new Array(10000).join(' ') }) // 添加時(shí)間監(jiān)聽 .on('cycle', event => { // 打印執(zhí)行時(shí)間 console.log(String(event.target)) }) // 完成后執(zhí)行觸發(fā)的事件 .on('complete', () => { console.log('最快的是:' + suite.filter('fastest').map('name')) }) // 執(zhí)行測(cè)試 .run({ async: true }) 復(fù)制代碼 代碼執(zhí)行結(jié)果如下: // join1000 x 146,854 ops/sec ±1.86% (88 runs sampled) // join10000 x 16,083 ops/sec ±1.06% (92 runs sampled) // 最快的是:join1000
在結(jié)果中,ops/sec表示的是每秒執(zhí)行的次數(shù),越大表示越好,每秒執(zhí)行次數(shù)上下相差的百分比,最后括號(hào)中的內(nèi)容表示共取樣多少次。
或者也可以使用JSBench.me工具進(jìn)行替換,網(wǎng)站測(cè)試截圖如下:
上面可以看待join1000的性能更好一些。
慎用全局變量
慎用全局變量,為什么要慎用呢?主要有以下幾點(diǎn):
全局變量定義在全局執(zhí)行上下文,是所有作用域鏈的頂端。每次查找的時(shí)候都從局部找到最頂端,在時(shí)間上會(huì)有所消耗。
全局執(zhí)行上下文一直存在于上下文的執(zhí)行棧,直到程序退出,才會(huì)被銷毀,內(nèi)存空間浪費(fèi)。
如果某個(gè)局部作用域出現(xiàn)了同名的變量則會(huì)遮蓋或者說污染全局變量 。
下面我們就來寫一段代碼,看一下全局變量與布局變量在執(zhí)行效率方面的差異,代碼如下:
... suite .add('全局變量', () => { // 該函數(shù)內(nèi)模擬全局作用域 let i, str = '' for (i = 0; i < 1000; i++) { str += i } }) .add('局部變量', () => { for (let i = 0, str = ''; i < 1000; i++) { str += i } }) ...
代碼運(yùn)行結(jié)果如下:
全局變量 x 158,697 ops/sec ±1.05% (87 runs sampled)
局部變量 x 160,697 ops/sec ±1.03% (90 runs sampled)
最快的是:局部變量
這些差異化不大,但能夠感知全局變量比局部的性能更差一些。
通過原型新增方法
為構(gòu)造函數(shù)增加實(shí)例對(duì)象需要的方法時(shí),盡量使用原型的方式添加,而不是構(gòu)造函數(shù)內(nèi)部進(jìn)行添加,我們可以看如下測(cè)試代碼:
... suite .add('構(gòu)造函數(shù)內(nèi)部添加', () => { function Person() { this.sayMe = function () { return '一碗周' } } let p = new Person() }) .add('原型方式內(nèi)部添加', () => { function Person() {} Person.prototype.sayMe = function () { return '一碗周' } let p = new Person() }) ...
代碼運(yùn)行結(jié)果如下:
構(gòu)造函數(shù)內(nèi)部添加 x 573,786 ops/sec ±1.97% (89 runs sampled)
原型方式內(nèi)部添加 x 581,693 ops/sec ±3.46% (80 runs sampled)
最快的是:構(gòu)造函數(shù)內(nèi)部添加
避免閉包中的內(nèi)存泄露
我們要避免閉包中的內(nèi)存泄露主要是因?yàn)樵陂]包會(huì)使得函數(shù)的變量過程中都被保存在內(nèi)存中,就會(huì)產(chǎn)生很大的內(nèi)存,這就是不能濫用閉包緣由,內(nèi)存過大就會(huì)造成頁面阻塞,嚴(yán)重可能導(dǎo)致內(nèi)存泄露。解決方法是,在退出函數(shù)之前,將不使用的局部變量全部刪除(即將局部變量重新賦值為null)。
避免使用屬性訪問方法
在JavaScript中的對(duì)象中,避免使用一些屬性訪問方法,這是因?yàn)镴avaScript中的所有屬性都是外部可見的。
示例代碼如下:
... suite .add('使用屬性訪問方法', () => { function Person() { this.name = '一碗周' this.getName = function () { return '一碗周' } } let p = new Person() let n = p.getName() }) .add('不使用屬性訪問方法', () => { function Person() { this.name = '一碗周' } let p = new Person() let n = p.name }) ...
代碼運(yùn)行結(jié)果如下:
使用屬性訪問方法 x 406,682 ops/sec ±2.33% (82 runs sampled)
不使用屬性訪問方法 x 554,169 ops/sec ±2.03% (85 runs sampled)
最快的是:不使用屬性訪問方法
for循環(huán)優(yōu)化
我們?cè)谑褂胒or循環(huán)時(shí),可以將有些必要的數(shù)據(jù)進(jìn)行緩存,就比如arr.length這種屬性,不需要每次判斷都獲取一下,從而優(yōu)化我們的代碼。
示例代碼如下:
... suite .add('正序', () => { let arr = new Array(100) let str = '' for (let i = 0; i < arr.length; i++) { str += i } }) .add('緩存', () => { let arr = new Array(100) let str = '' for (let i = arr.length; i; i--) { str += i } }) .add('緩存的另一種寫法', () => { let arr = new Array(100) let str = '' for (let i = 0, l = arr.length; i < l; i++) { str += i } }) ...
代碼運(yùn)行結(jié)果如下:
正序 x 1,322,889 ops/sec ±1.36% (86 runs sampled)
緩存 x 1,356,696 ops/sec ±0.70% (92 runs sampled)
緩存的另一種寫法 x 1,383,091 ops/sec ±0.70% (93 runs sampled)
最快的是:緩存的另一種寫法
選擇最優(yōu)的循環(huán)方式
我們現(xiàn)在常用的循環(huán)有forEach、for和for...in循環(huán),這幾種那個(gè)是性能最優(yōu)的呢,測(cè)試代碼如下:
... suite .add('forEach', () => { let arr = new Array(100) let str = '' arr.forEach(i => { str += i }) }) .add('for...in', () => { let arr = new Array(100) let str = '' for (i in arr) { str += i } }) .add('for', () => { let arr = new Array(100) let str = '' for (let i = 0, l = arr.length; i < l; i++) { str += i } }) ...
代碼運(yùn)行結(jié)果如下:
forEach x 4,248,577 ops/sec ±0.89% (86 runs sampled)
for...in x 4,583,375 ops/sec ±1.15% (91 runs sampled)
for x 1,343,871 ops/sec ±1.91% (88 runs sampled)
最快的是:for...in
由運(yùn)行結(jié)果可以看出我們可以盡量使用for...in或者forEach循環(huán),減少使用for循環(huán)。
減少判斷層級(jí)
減少判斷層級(jí)就是減少一些if語句的嵌套,如果是一些必要的條件我們可以通過單層if結(jié)合return直接跳出函數(shù)的執(zhí)行,關(guān)于優(yōu)化前與優(yōu)化后的代碼執(zhí)行比對(duì)如下所示:
... /*** 接收兩類文件,zip 和 rar* 壓縮包的大小限制為 10 兆* / suite .add('嵌套寫法', () => { function uploadFile(suffix, size) { // 允許上傳的后綴名 const suffixList = ['.zip', '.rar'] const M = 1024* 1024 if (suffixList.includes(suffix)) { if (size <= 10* M) { return '下載成功' } } } uploadFile('.zip', 1* 1024* 1024) }) .add('減少判斷寫法', () => { function uploadFile(suffix, size) { // 允許上傳的后綴名 const suffixList = ['.zip', '.rar'] const M = 1024* 1024 if (!suffixList.includes(suffix)) return if (size > 10* M) return return '下載成功' } uploadFile('.zip', 1* 1024* 1024) }) ...
代碼運(yùn)行結(jié)果如下:
嵌套寫法 x 888,445,014 ops/sec ±2.48% (88 runs sampled)
減少判斷寫法 x 905,763,884 ops/sec ±1.35% (92 runs sampled)
最快的是:減少判斷寫法,嵌套寫法
這方法差不大,但它并不適用嵌套的代碼比普通代碼更優(yōu)一些。
減少作用域鏈查找層級(jí)
減少代碼中作用域鏈的查找也是代碼優(yōu)化的一種方法,如下代碼展示了兩者的區(qū)別:
... suite .add('before', () => { var name = '一碗粥' function sayMe() { name = '一碗周' function print() { var age = 18 return name + age } print() } sayMe() }) .add('after', () => { var name = '一碗粥' function sayMe() { var name = '一碗周' // 形成局部作用域 function print() { var age = 18 return name + age } print() } sayMe() }) ...
代碼運(yùn)行結(jié)果如下:
before x 15,509,793 ops/sec ±7.78% (76 runs sampled)
after x 17,930,066 ops/sec ±2.89% (83 runs sampled)
最快的是:after
上面代碼只是為了展示區(qū)別,并沒有實(shí)際意義。
減少數(shù)據(jù)讀取次數(shù)
如果對(duì)象中的某個(gè)數(shù)據(jù)在一個(gè)代碼塊中使用兩遍以上,這樣的話將其進(jìn)行緩存從而減少數(shù)據(jù)的讀取次數(shù)來達(dá)到更優(yōu)的一個(gè)性能,
測(cè)試代碼如下:
... var userList = { one: { name: '一碗周', age: 18, }, two: { name: '一碗粥', age: 18, }, } suite .add('before', () => { function returnOneInfo() { userList.one.info = userList.one.name + userList.one.age } returnOneInfo() }) .add('after', () => { function returnOneInfo() { let one = userList.one one.info = one.name + one.age } returnOneInfo() }) ...
代碼運(yùn)行結(jié)果如下:
before x 222,553,199 ops/sec ±16.63% (26 runs sampled)
after x 177,894,903 ops/sec ±1.85% (88 runs sampled)
最快的是:before
字面量與構(gòu)造式
凡是可以使用字面量方式聲明的內(nèi)容,絕對(duì)是不可以使用構(gòu)造函數(shù)的方式聲明的,兩者在性能方面相差甚遠(yuǎn),代碼如下:
... suite .add('before', () => { var str = new String('string') }) .add('after', () => { var str = 'string' }) ...
代碼運(yùn)行結(jié)果如下:
before x 38,601,223 ops/sec ±1.16% (89 runs sampled)
after x 897,491,903 ops/sec ±0.92% (92 runs sampled)
最快的是:after
分享已完畢,請(qǐng)大家關(guān)注更多后續(xù)精彩內(nèi)容。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/128003.html
摘要:翻譯正文第一次聲明變量時(shí),請(qǐng)不要忘記使用關(guān)鍵字聲明使用代替空字符串轉(zhuǎn)成布爾值都為每行代碼的末尾最好都加上個(gè)分號(hào)最好給對(duì)象都添加上構(gòu)造函數(shù)在使用和盡量小心。 翻譯介紹 翻譯標(biāo)題:45 Useful JavaScript Tips, Tricks and Best Practices 翻譯來源:http://modernweb.com/2013/12/23/45-useful-java...
摘要:特意對(duì)前端學(xué)習(xí)資源做一個(gè)匯總,方便自己學(xué)習(xí)查閱參考,和好友們共同進(jìn)步。 特意對(duì)前端學(xué)習(xí)資源做一個(gè)匯總,方便自己學(xué)習(xí)查閱參考,和好友們共同進(jìn)步。 本以為自己收藏的站點(diǎn)多,可以很快搞定,沒想到一入?yún)R總深似海。還有很多不足&遺漏的地方,歡迎補(bǔ)充。有錯(cuò)誤的地方,還請(qǐng)斧正... 托管: welcome to git,歡迎交流,感謝star 有好友反應(yīng)和斧正,會(huì)及時(shí)更新,平時(shí)業(yè)務(wù)工作時(shí)也會(huì)不定期更...
摘要:更多資源請(qǐng)文章轉(zhuǎn)自月份前端資源分享視頻前端技術(shù)論壇融合不可錯(cuò)過的迷你庫測(cè)試框架實(shí)例教程為你詳細(xì)解讀請(qǐng)求頭的具體含意解析的庫如果要用前端框架,開發(fā)流程是怎樣的與有什么區(qū)別正確使用的方法是什么流程圖插件小如何讓元素只能輸入純文本前端技術(shù)中 更多資源請(qǐng)Star:https://github.com/maidishike... 文章轉(zhuǎn)自:https://github.com/jsfront...
摘要:,谷歌給的一份性能指南和最佳實(shí)踐。目前而言,前端社區(qū)有三大框架和。隨后重點(diǎn)講述了和兩大前端框架,給出了大量的文章教程和相關(guān)資源列表。我認(rèn)為,使用函數(shù)式編程方式,更加符合后端程序員的思路,而是更符合前端工程師習(xí)慣的框架。 showImg(https://segmentfault.com/img/bVbjQAM?w=1142&h=640); 這個(gè)是我訂閱 陳皓老師在極客上的專欄《左耳聽風(fēng)》...
摘要:,谷歌給的一份性能指南和最佳實(shí)踐。目前而言,前端社區(qū)有三大框架和。隨后重點(diǎn)講述了和兩大前端框架,給出了大量的文章教程和相關(guān)資源列表。我認(rèn)為,使用函數(shù)式編程方式,更加符合后端程序員的思路,而是更符合前端工程師習(xí)慣的框架。 showImg(https://segmentfault.com/img/bVbjQAM?w=1142&h=640); 這個(gè)是我訂閱 陳皓老師在極客上的專欄《左耳聽風(fēng)》...
閱讀 570·2023-03-27 18:33
閱讀 760·2023-03-26 17:27
閱讀 658·2023-03-26 17:14
閱讀 611·2023-03-17 21:13
閱讀 545·2023-03-17 08:28
閱讀 1833·2023-02-27 22:32
閱讀 1329·2023-02-27 22:27
閱讀 2211·2023-01-20 08:28