JavaScript 性能优化

代码优化

如何精准得测试js性能

采集大量得执行样本进行数学统计和分析

1. Benchmark

npm i benchmark  // 越大性能越好(Ops/sec)
const Benchmark = require('benchmark');
const suite = new Benchmark.Suite;

suite
    .add('RegExp#test', function () {
    	// 这里放入对比代码
    })
    .add('String#indexOf', function () {
    	// 这里放入对比代码
    })
    // add listeners
    .on('cycle', function (event) {
        console.log(String(event.target));
    })
    .on('complete', function () {
        console.log('Fastest is ' + this.filter('fastest').map('name'));
    })
    // run async
    .run({ 'async': true });

2. jsBench.me

js代码执行效率的一个网站
在这里插入图片描述

优化方法

1. 慎用全局变量

在这里插入图片描述

    .add('RegExp#test', function () {
        var i, str = ''
        for (i = 0; i < 1000; i++) {
            str += i
        }
    })
    .add('String#indexOf', function () {
        for (let i = 0; i < 1000; i++) {
            let str = ''
            str += i
        }
    })

2. 缓存全局变量

将使用中无法避免的大量需要重复的全局变量缓存到局部(document)

    .add('RegExp#test', function () {
        let oBtn1 = document.getElementById('btn1')
        let oBtn1 = document.getElementById('btn3')
        let oBtn1 = document.getElementById('btn5')
        let oBtn1 = document.getElementById('btn7')
        let oBtn1 = document.getElementById('btn9')
    })
    .add('String#indexOf', function () {
        let obj = document
        let oBtn1 = obj.getElementById('btn1')
        let oBtn1 = obj.getElementById('btn3')
        let oBtn1 = obj.getElementById('btn5')
        let oBtn1 = obj.getElementById('btn7')
        let oBtn1 = obj.getElementById('btn9')
    })

3. 在原型对象上新增实例对象需要的方法

    .add('RegExp#test', function () {
        var fn1 = function () {
            this.foo = function () {
                console.log(111);
            }
        }
        let f1 = new fn1()
    })
    .add('String#indexOf', function () {
        var fn2 = function () {
            fn2.prototype.foo = function () {
                console.log(111);
            }
        }
        let f2 = new fn2()
    })

4. 避开闭包的陷阱

使用不当很容易出现内存泄漏
不要为了闭包而闭包

function foo(){
    var el = document.getElementById('btn')
    el.onclick = function(){
        console.log(el.id);
    }
    el = null // 当浏览器的document对象被引用2次,且该对象被删除的时候会照成内存泄漏
}

5. 避免属性访问方法使用

js不需属性的访问方法,所有属性都是外部可见的
使用属性方法只会增加一层重定义,没有访问的控制力

    .add('RegExp#test', function () {
        function Person(){
            this.name = 'icoder'
            this.getAge = function(){
                return this.age
            }
        }
        const p1 = new Person()
        const a =  p1.getAge()
    })
    .add('String#indexOf', function () {
        function Person(){
            this.name = 'icoder'
            this.age = 18
        }
        const p2 = new Person()
        const b =  p2.age
    })

6. For循环优化

    .add('RegExp#test', function () {
        let arr = [1, 2, 3, 4, 5]
        for (var i = 0; i < arr.length; i++) {
            console.log(i);
        }
    })
    .add('String#indexOf', function () {
        let arr = [1, 2, 3, 4, 5]
        for (var i = 0, len = arr.length; i < len; i++) { // 少了每次都需要重新计算长度
            console.log(i);
        }
    })

7. 选择最优的循环方法

在这里插入图片描述

8. 文档碎片优化节点的添加

    .add('RegExp#test', function () {
        for (let i = 0; i < 10; i++) {
            var oP = document.createElement('p')
            oP.innerHTML = i
            document.body.appendChild(oP)
        }
    })
    .add('String#indexOf', function () {
        const frageEle = document.createDocumentFragment()
        for (let i = 0; i < 10; i++) {
            var oP = document.createElement('p')
            oP.innerHTML = i
            frageEle.appendChild(oP)
        }
        document.body.appendChild(frageEle)
    })

9. 克隆优化节点操作

    .add('RegExp#test', function () {
        for (let i = 0; i < 3; i++) {
            let oP = document.createElement('p')
            oP.innerHTML = i
            document.body.appendChild(oP)
        }
    })
    .add('String#indexOf', function () {
        var oldP = document.getElementById('box1')
        for (let i = 0; i < 3; i++) {
            let newP = oldP.cloneNode(false)
            oP.innerHTML = i
            document.body.appendChild(newP)
        }
    })

10. 直接量替换 new Objec

    .add('RegExp#test', function () {
        let a1 = new Array(3)
        a1[0] = 1
        a1[1] = 2
        a1[2] = 3
    })
    .add('String#indexOf', function () {
        const a = [1, 2, 3]
    })

11. 减少判断层级

// function doSomething(part, chapter) {
//     const parts = ['ES2016', '工程化', 'Vue', 'React']
//     if (part) {
//         if (parts.includes(part)) {
//             console.log('属于当前课程');
//             if (chapter > 5) {
//                 console.log('您需要提供vip身份');
//             }
//         }
//     } else {
//         console.log('请确认模块信息');
//     }
// }

function doSomething(part, chapter) {
    const parts = ['ES2016', '工程化', 'Vue', 'React']
    if (!part) {
        console.log('请确认模块信息');
        return
    }
    if (!parts.includes(part)) return
    console.log('属于当前课程');
    if (chapter > 5) {
        console.log('您需要提供vip身份');
    }
}

12. 减少作用域链查找层级

缺点:消耗内存空间;优点:因为向上查找的作用域层级更近了,查找速度更快

// let name = 'xh'
// function foo() {
//     name = 'cx'
//     function baz() {
//         var age = 38
//         console.log(age);
//         console.log(name);
//     }
//     baz()
// }

let name = 'xh'
function foo() {
   let name = 'cx'
    function baz() {
        var age = 38
        console.log(age);
        console.log(name);
    }
    baz()
}

13. 减少数据读取次数

数据表现形式
字面量,局部变量,数组元素,对象属性
字面量,局部变量是最快的,因为他们都可以放在栈区当中
而数组元素,对象属性会慢一些,因为对象上往往会考虑到原型链的查找,和作用域链的道理一样
减少嵌套层级或深度(缺点是内存换时间),对象数据提前缓存,后续直接使用

// var oBox = document.getElementById('skip')
// function hasEle(ele,cls){
//     return ele.className == cls
// }
// console.log(hasEle(oBox,'skip'));

var oBox = document.getElementById('skip')
function hasEle(ele,cls){
    let clsname = ele.className
    return clsname == cls
}
console.log(hasEle(oBox,'skip'));

14. 字面量与构造式

// let test = () => {
//     let obj = new Object()
//     obj.name = 'cx'
//     return obj
// }

let test = () => {
    let obj = {
        name:'cx'
    }
    return obj
}

console.log(test());
// let str1 = 'cx'
let str1 = new String('cx')
console.log(str1);

15. 减少循环体中活动

// let test = () => {
//     let arr = ['cx', 'hello']
//     for (i = 0; i < arr.length; i++) {
//         console.log(document.getElementById('a'));
//         console.log(arr[i]);
//     }
// }

let test = () => {
    let arr = ['cx', 'hello']
    let doc = document.getElementById('a')
    for (i = 0, len = arr.length; i < len; i++) {
        console.log(doc);
        console.log(arr[i]);
    }
}

16. 减少声明及语句数

代码执行前有个编译的过程(短),词法分析遇到关键字要做拆分-语法分析-生成语法树-再去转代码-并执行

// let test = (ele) => {
//     let w = ele.offsetWidth
//     let h = ele.offsetHight
//     return w * h
// }

let test = (ele) => {
    return ele.offsetWidth * ele.offsetHight
}
console.log(test(document.getElementById('a')));
// const test = () => {
//     let name = 'cx'
//     let slogan = 'hello'
//     return name + slogan
// }

const test = () => {
    let name = 'cx',
        slogan = 'hello'
    return name + slogan
}
console.log(test())

17. 采用事件绑定(委托)

// let list = document.querySelectorAll('li')
// function showTxt(e) {
//     console.log(e.target.innerHTML);
// }
// for(let item of list){
//     item.onclick = showTxt
// }

let ul = document.getElementById('ul')
ul.addEventListener('click', showTxt, true)
function showTxt(e) {
    let obj = e.target
    if (obj.nodeName.toLowerCase() === 'li') {
        console.log(obj.innerHTML);
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值