本篇文章為大家帶來了關於javascript的相關知識,主要介紹了總結分享10個JavaScript程式碼優化小tips,文章圍繞主題展開詳細的內容介紹,具有一定的參考價值,希望對大家有幫助。
【相關推薦:javascript影片教學、web前端】
想要做到JavaScript的程式碼最佳化,首先要做的是準確的測試JavaScript的程式碼執行時間。其實需要做的就是收集大量的執行樣本進行數學統計和分析,這裡我們使用的是benchmark.js
來偵測程式碼的執行情況。
首先我們需要在專案中安裝依賴,程式碼如下:
yarn add benchmark --save # 或者 npm i benchmark --save
然後我們寫一個測試程式碼,如下所示:
const Benchmark = require('benchmark') const suite = new Benchmark.Suite() // 添加测试 suite /** * add() 方法接受两个参数,其中第一个表示测试的名称,第二个表示测试的内容,他是一个函数* / .add('join1000', () => { new Array(1000).join(' ') }) .add('join10000', () => { new Array(10000).join(' ') }) // 添加时间监听 .on('cycle', event => { // 打印执行时间 console.log(String(event.target)) }) // 完成后执行触发的事件 .on('complete', () => { console.log('最快的是:' + suite.filter('fastest').map('name')) }) // 执行测试 .run({ async: true }) 复制代码
程式碼執行結果如下:
// join1000 x 146,854 ops/sec ±1.86% (88 runs sampled)
// join10000 x 16,083 ops /sec ±1.06% (92 runs sampled)
// 最快的是:join1000
在結果中,ops/sec
表示的是每秒執行的次數,當然越大越好,緊接著是每秒執行次數上下相差的百分比,最後括號中的內容表示共取樣多少次。我們可以看到,都是join1000
的表現更好一些(我感覺我在說廢話)。
這裡所說的慎用全域變量,為什麼要慎用呢?主要有以下幾點:
下面我們就來寫一段程式碼,看看全域變數與佈局變數在執行效率上的差異,程式碼如下:
... suite .add('全局变量', () => { // 该函数内模拟全局作用域 let i, str = '' for (i = 0; i < 1000; i++) { str += i } }) .add('局部变量', () => { for (let i = 0, str = ''; i < 1000; i++) { str += i } }) ...
程式碼運行結果如下:
全域變數x 158,697 ops/sec ±1.05% (87 runs sampled)
局部變數x 160,697 ops/sec ±1.03% (90 runs sampled)
最快的是:局部變數
雖然說差異不大,但是我們可以感知全域變數比局部的效能更差一些。
為建構子增加實例物件所需的方法時,盡量使用原型的方式添加,而不是建構函式內部進行添加,我們可以看如下測試程式碼:
... suite .add('构造函数内部添加', () => { function Person() { this.sayMe = function () { return '一碗周' } } let p = new Person() }) .add('原型方式内部添加', () => { function Person() {} Person.prototype.sayMe = function () { return '一碗周' } let p = new Person() }) ...
程式碼運行結果如下:
建構子內部新增x 573,786 ops/sec ±1.97% (89 runs sampled)
原型方式內部添加x 581,693 ops/sec ±3.46% (80 runs sampled)
最快的是:構造函數內部添加
由於閉包會讓函數中的變數都保存在記憶體中,記憶體消耗很大,所以不能濫用閉包,否則會造成網頁的效能問題,嚴重可能導致記憶體外洩。解決方法是,在退出函數之前,將不使用的局部變數全部刪除 (即將局部變數重新賦值為null
)。
在JavaScript中的物件中,避免使用一些屬性存取方法,這是因為JavaScript中的所有屬性都是外部可見的。
範例程式碼如下:
... 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 }) ...
程式碼執行結果如下:
使用屬性存取方法x 406,682 ops /sec ±2.33% (82 runs sampled)
不使用屬性存取方法x 554,169 ops/sec ±2.03% (85 runs sampled)
最快的是:不使用屬性存取方法
我們在使用for迴圈時,可以將有些必要的資料進行緩存,就例如arr.length
這種屬性,不需要每次判斷都取得一下,從而優化我們的程式碼。
範例程式碼如下:
... 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 } }) ...
程式碼運行結果如下:
選擇最優的迴圈方式我們現在常用的迴圈有正序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最快的是:快取的另一種寫法
forEach、
for 和
for...in循環,這幾種那個是效能最優的呢,測試程式碼如下:
... 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 } }) ...
程式碼運行結果如下:
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
由运行结果可以看出我们可以尽量使用for...in
或者forEach
循环,减少使用for
循环。
减少判断层级就是减少一些if
语句的嵌套,如果是一些必要的条件我们可以通过单层if
结合return
直接跳出函数的执行,关于优化前与优化后的代码执行比对如下所示:
... /*** 接收两类文件,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) }) ...
代码运行结果如下:
嵌套写法 x 888,445,014 ops/sec ±2.48% (88 runs sampled)
减少判断写法 x 905,763,884 ops/sec ±1.35% (92 runs sampled)
最快的是:减少判断写法,嵌套写法
虽然说差距并不是很大,但是不适用嵌套的代码比普通代码更优一些。
减少代码中作用域链的查找也是代码优化的一种方法,如下代码展示了两者的区别:
... 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() }) ...
代码运行结果如下:
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
上面代码只是为了展示区别,并没有实际意义。
如果对象中的某个数据在一个代码块中使用两遍以上,这样的话将其进行缓存从而减少数据的读取次数来达到更优的一个性能,
测试代码如下:
... 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() }) ...
代码运行结果如下:
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
凡是可以使用字面量方式声明的内容,绝对是不可以使用构造函数的方式声明的,两者在性能方面相差甚远,代码如下:
... suite .add('before', () => { var str = new String('string') }) .add('after', () => { var str = 'string' }) ...
代码运行结果如下:
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
【相关推荐:javascript视频教程、web前端】
以上是總結分享10個JavaScript程式碼優化小技巧的詳細內容。更多資訊請關注PHP中文網其他相關文章!