js性能优化
本文主要介绍js性能优化相关知识。
作用域相关:
1、避免全局查找
我们知道作用域链是局部在前,全局在后的,那么访问全局变量就需要去遍历作用域链,其开销自然就比局部的更大。
2、避免 with语句
with会创建自己的作用域,也就是说会增加其中执行代码的作用域链的长度,会造成额外的作用域链查找。
选择正确方法:
1、避免不必要的属性查找
在计算机科学中,算法的复杂度使用O符号来表示。这里我简单的用语言来描述一下。
最简单的算法是常数值,即O(1),其不管有多少值,执行 的时间都是恒定的,一般用来表示简单值和存储在变量中的值。
O(log n)总的执行时间和值的熟练相关,但是要完成算法并不一定要获取每个值。例如:二分查找
O(n)总执行时间和值的数量直接相关。例如:遍历某个数组中的所有元素。
O(n的平方)总执行时间和值的数量有关,每个值只是要获取n次。例如:插入排序。
光这样说我相信大部分都是一脸懵,下面用一些js代码来直观的了解一下:
let value = 5 let num = 10 + value console.log(num)
这段代码中进行了4次常量值的查找,5、10、vallue、num,这段代码的整体复杂度被认为是O(1),访问数组元素同样也被认为是O(1)
let values = {one:1,two:2} let num = values.one + values.two console.log(sum)
访问对象上的属性被认为是一个O(n)操作,因为必须在原型链中对拥有该名称的属性进行一次搜索,这段代码使用两次属性查找来计算num的值,如果只是一两次并不会导致显著的性能问题,但一旦多起来则会很明显。
我们要注意单个值的多重属性查找。比如:
let query = window.loaction.href.substring(window.loaction.href.indexOf('?'))
这里我们重复对window.loaction.href这个属性进行了查找,这个语句的属性查找总共有6次(可以看有几个.),重复了一次,就造成了性能的缺失,正确的做法是将window.loaction.href这个属性值先用常量存储起来,这样之后的操作就都是O(1)操作了。
2、优化循环
a、减值迭代,很多情况下,从最大值开始,在循环中不断减值的迭代器更加高效。
b、简化终止条件,每次循环过程都会计算,所以要尽可能的简化终止条件,即最好是O(1)操作
c、简化循环体,循环体执行是最多的,所以也要尽可能的简化,同上。
d、使用后测试循环,最常用的是for和while循环,这2者都是前测试循环。而如do-while这种后测试循环可以避免最初终止条件的计算,因此运行速度更快。
3、展开循环
当循环的次数是确定的,消除循环并使用多次函数调用往往更快,这样可以消除建立循环和处理终止条件的额外开销。如果迭代次数不能事先确定的话,可以取了解一下一种叫做Duff装置的技术,这里就不做详细阐述了。
4、避免双重解释
即避免出现需要安装JavaScript解释的字符串。
5、其它注意事项
原生方法较快;switch语句比一系列的if-else快;位运算符较快。
最小化语句数
1、变量声明
var a; var b; var c, d;
前者是2个语句,后者是一个语句。
2、插入迭代值
var name = value[i] i++ var name = value[i++]
前者和后者的做的事情是一样的,++是后缀操作符。
3、使用数组和对象字面量
var arr = new Array() arr[0] = 1 arr[1] = 2 var arr = [1, 2]
前者3条语句,而后者只有1条。
DOM交互优化
在js各个方面中,DOM是最慢的一部分!DOM操作与交互要消耗大量的实际,其要处理的信息特别的多,因此理解如何优化与DOM的交互是至关重要的。
1、最小化现场更新
现场更新的意思是,你访问的DOM部分,是已经显示的页面的一部分。
比如你循环添加DOM节点的时候,可以使用文档片段来构建DOM解构,再DOM渲染。以下是代码:
var list = document.getElementById('myList'), fragment = documemnt.createDocumentFragment(), item,i; for(i=10; i>=0; i++){ item = document.createElement('li'); fragment.appendChild(item) item.appendChild(document.createTextNode('Item' + i)); } list.appendChild(fragment);
在这个例子中,只有一次现场更新。
2、使用innerHTML
innerHTML也是一种创建DOM节点的方法,相较于createElement等方法,其优势在于,在大的DOM更改时效率比标准的DOM方法快的多。因为其并不是基于js的DOM调用,而是后台创建的HTML解析器内部的DOM来创建。
在使用innerHtml的同时我们也要注意最小化调用它的次数。
3、使用事件代理
页面是的事件处理程序的数量和页面响应用户交互的速度之间有个负相关,所以,在用户交互上我们最好使用事件代理。
任何可以冒泡的事件都不仅仅可以在事件目标上进行处理,目标的任何祖先节点上也能处理。如果可能,在文档级别附加事件处理程序,这样可以处理整个页面的事件。
4、注意HTMLCollection
查询HTMLCollection 的开销是很贵的,最小化访问HTMLCollection 的次数可以极大地改进脚本的性能。