高性能的JavaScript

加载和执行

每个<script>标签初始化下载都会阻塞页面渲染,所以减少页面的<script>标签数量可以起到优化作用,内嵌脚本外链脚本通用,另外HTTP会带来的额外的性能消耗,下载一个100KB的文件比下载4个25KB的文件更快,所以可以通过进行脚本的合并去1、减少<script>标签数量 2、减少HTTP请求带来的消耗(针对外链脚本)。

数据存取

1.字面量:代表自身,无特定位置,包括:字符串、数字、布尔值、对象、数组、函数、正则表达式及null和undefined
2.本地变量:var/let/const关键字定义的数据存储单元
3.数组元素:存储在JavaScript数组对象内部,以数字为索引,下标从0开始
4.对象成员:存储在JavaScript对象内部,以字符串为索引
从一个字面量和本地变量中存取数据时的性能消耗极小(可忽略),数组和对象则稍高一些。
建议:尽量使用字面量和局部变量(局部变量在方法运行过后会自行释放,用完手动置为null或undefined也行),减少使用对象和数组,比如某作用域内的值呗函数引用一次以上,就可以把它存储到局部变量中来使用

算法及流程控制

  1. for in循环可以枚举任何对象的属性名(不是值),但是for in比其他三个循环明显要慢,所以除非要迭代一个属性数量未知的对象,否则避免使用for in循环,如果遍历一个属性数量已知属性列表,其他循环比for in快

  2. 假设以上四种循环类型性能一样,可以从两个方面去优化循环的性能:
    (当循环体复杂度为X时,优化方案优先减少循环体的复杂度,循环体复杂度大于X时,优化方案优先减少迭代次数 )
    1.每次迭代的事务(减少循环体的复杂度)
    2.迭代的次数(减少循环的次数,百度‘达夫设备’),可以这么理解,达夫设备就是拆解循环,比如遍历一个长度为100的数组,普通情况下循环体执行100次,达夫设备的思想是把100次拆为每次循环执行多次(n表示)100对n取余,执行取余次数,再执行100除以n(下舍)次循环,这个循环体执行n次普通循环体的操作
    达夫设备代码:(这个8就是我说的n)

    var a = [1,2,3,4,5,6,7,8,9,10]
    var it = Math.floor(a.length / 4),st = a.length % 4,i = 0
    do{
    switch(st) {
    case 0: console.log(0,a[i++]);
    case 7: console.log(7,a[i++]);
    case 6: console.log(6,a[i++]);
    case 5: console.log(5,a[i++]);
    case 4: console.log(4,a[i++]);
    case 3: console.log(3,a[i++]);
    case 2: console.log(2,a[i++]);
    case 1: console.log(1,a[i++]);
    }
    st = 0
    }while(--it)
  3. 最小化属性查找:

    for(var i = 0, len = arr.length; i < len; i++){
    ...
    }

    基于函数的迭代:forEach()
    forEach遍历一个数组的所有成员,并执行一个函数

    arr.forEach(function(value, index, array){
    ...
    })

    但是所有情况下。基于循环的迭代比基于函数的迭代快8倍,在运行速度要求严格时,基于循环的迭代优先于基于函数的迭代

  4. if-else对比switch:
    当条件较少时 使用if-else更易读,而当条件较多时if-else性能负担比switch大,易读性也没switch好。
    优化if-else的方法是:尽可能的把可能出现的条件放在首位,比如:

    var i = Math.random(1);   
    if(i <= 0.8){ //i小于0.8是几率最大的,如果i的值满足i <= 0.8 后面的条件就不会再判断了
    ...
    }else if(i > 0.8 && i <= 0.9){
    ...
    }else{
    ...
    }

    当条件很多的时候:(比如10个和10个以上),避免使用条件语句if-else、switch是最佳方式是使用hash表

* Memoization

减少工作量就是最好的性能优化技术(你可以理解为,砍需求是为了性能优化)  
Memoization避免重复工作,缓存前一个计算的结果为后面的计算所用
  1. (do-while, while) > for > forEach

    forEach为函数调用(慢在函数查找

    达夫设备 速度和 (do-while, while) 相差无几,有时更慢,但是比其他循环更快

实践

  1. //创建一个对象 较慢
    var myObject = new Object();
    my0bject.name = "Nicholas";
    my0bject.count =50;
    //较快 直接量
    var myObject ={
    name: "Nicholas"
    count: 50
    }
  • 尽量使用直接量创建对象和数组。直接量的创建和初始化都比非直接量形式要快。·避免做重复的工作。当需要检测浏览器时,可使用延迟加载或条件预加载。
  • 在进行数学计算时,考虑使用直接操作数字的二进制形式的位运算。
  • JavaScript的原生方法总会比你写的任何代码都要快。尽量使用原生方法。