web性能实践
2019-05-07 本文已影响0人
萘小蒽
一. 作用域
前面我们了解作用域概念的以及作用域链是如何运作的。
- 随着作用域链中的作用域数量的增加,访问当前作用域意外的变量的时间也在增加。
- 查找作用域链外层变量,需要遍历作用域链,所以访问全局变量要比访问局部变量慢。
1. 避免全局查找
优化js性能最重要的就是注意全局查找。使用全局变量或者函数肯定要比局部的开销更大,因为涉及作用域链上的查找。
function updataUI(){
var ings = document.getElementsByTagName("img");
for( var i=0,len = imgs.length; i < len ;i++){
imgs[i].title = document.title + "image" + i
}
var msg = document.getElementById('msg');
msg.innerHTML = "Update complete."
}
上面的函数包含了三个对于全局
document
对象的引用。如果页面上有多个图片,那么for
循环中的document
的引用就会被执行多次甚至上百次。
通过创建一个指向document
对象的局部变量,就可以通过限制一次全局查找来改进这个函数的性能:
function updataUI(){
var doc = document;
var ings = doc .getElementsByTagName("img");
for( var i=0,len = imgs.length; i < len ;i++){
imgs[i].title = doc .title + "image" + i
}
var msg = doc .getElementById('msg');
msg.innerHTML = "Update complete."
}
2. 选择正确方法
和 语言一样,性能问题的一部分是和用于解决问题的算法或者方法有关的。
- 避免不必要的属性查找
计算科学中,算法的复杂度是使用O符号来表示的。
标记 | 名称 | 描述 |
---|---|---|
O(1) |
常数 |
不管有多少值,执行时间都是恒定的,一般表示简单值和存储在变量中的值 |
O(log.n) |
对数 |
总的执行时间和值的数量相关,但是要完成算法并不一定要获取每个值。例如 二分查找
|
O(n) |
线性 |
总执行时间和值的数量 直接 相关。例如:遍历某个数组中的元素
|
O(n²) |
平方 |
总执行时间和值的数量有关。每个值至少获取n次。例如: 插入排序
|
O(1)
常数-----指代字面值和存储在变量中的值;如下:
//常数例子
var value = 5;
var sum = 10 + value;
alert(sum)
上面的代码执行了四次常量值查找:数字
5
和10
,变量value
、sum
。这段代码的整体复杂度被认为是O(1)
。
//常数例子
var values = [:5 , 10];
var sum = values[0] + values[1];
console.log(sum)
访问数组的元素也是一个
O(1)
操作,和简单的变量查找效率一样。
O(n)
------线性查找要比常数和对数复杂的多,比如访问对象上的属性,花费的时间更多,因为必须要在其原型链中对拥有该名称的属性进行一次搜索。
//线性例子1
var values = { first: 5, second: 10 };
var sum = values .first + values.second;
console.log(sum);
上面的例子使用了两次属性查找来计算sum的值。一两次可能并不会导致明显的性能问题,但是进行成百上千次肯定会减慢执行速度。
//线性例子2
var query = window.location.href.substring(window.location.href.indexof('?'));
上面的代码有6次属性查找,
window.location.href.substring
三次,window.location.href.indexof
又三次,(数一数代码中点的数量,确定属性查找的次数);
为了避免上个线性例子2的性能影响,我们可以将多次用到的对象属性,存储在局部变量中:
var url = window.location.href;
var query = url.substring(url.indexof('?'));
上面第一次访问该属性是
O(n)
,而存储在局部变量后,访问都是O(1)
。总共4次属性查找,相对于6次节省了33%,更大的脚本中进行这种优化,会获得更多性能上的改进。
-
优化循环
循环是编程中最常见的结构,js 就更不用说了,所以优化循环是性能优化过程中很重要的一部分。
一个循环的基本优化步骤如下:
- 减值迭代——大多数循环使用一个从0开始、增加到某个特定值得迭代器。在很多情况下,从最大值开始在循环中不断减值的迭代器更加高效。
- 简化终止条件——每次循环过程都会计算终止条件,所以必须保证它尽可能快。也就是避免属性查找或者其他
O(n)
的操作。- 简化循环体——循环体是执行最多的,所以要确保其被最大限度地优化,确保没有某些可以被很容易移除循环的密集计算。