JavaScript性能优化

JavaScript性能优化

自从JavaScript诞生以来,用这门语言编写网页的开发人员 有了极大的增长,与此同时,JavaScript
代码的执行效率也越来越受关注,所以我结合《JavaScript高级程序设计(第三版)》总结出了一共四大点优化性能的方法。

一、注意作用域

  1. 避免全局查找 ,可能优化脚本性能最重要的就是要注意全局查找。使用全局变量和函数肯定要比局部的开销更大,因为要涉及作用域链上的查找;
function fun(){
   /**	
   *优化下面语句
   *  console.log( window.location.href );
   *  console.log( window. location.hostname);
   */
   var location = window.location;
   console.log(location.href);
   console.log(location.hostname);
}

首先将window.location对象存在本地的location变量中,在余下的代码中替换原来的window.location,与原来的版本相比,现在的函数就只有一次全局查找,肯定更快。

  1. 避免with语句 ,在性能非常重要的地方必须避免使用with语句,with语句会创建自己的作用域,因此会增加其中执行的代码的作用域链的长度。
   /**	
   *优化下面方法
   *  function updateBody(){
   * 	with(document.body){
   * 		alert(tagname);
   * 		innerHTML = "hello";
   * 	}
   * }
   */
   function updateBody(){
   	var body= document.body;
   	alert(body.tagname);
   	body.innerHTML = "hello";
   }

将document.body存储在局部变量中省去了额外的全局查找,并且阅读起来比with语句版本更好,我们明确知道tagname和innerHTML是属于哪个对象的。

二、选择正确方法

1.避免不必要的属性查找:最简单,最快捷的算法是常数值

/** 优化以下语句
* var values  = {first: 5, second: 10};
* var sum = values.first + values.second;
*/

var value = [5,10]
var sum = values[0] + values[1];

使用变量和数组要比访问对象上的属性更加有效率,因为对象是一个O(n)操作,常数值为O(1),对象上的任何属性查找都要比访问变量或者数组花费更长的时间。

2.优化循环是对性能优化过程中很重要的一部分,由于它们会反复运行同一段代码,从而自动的增加执行时间。
(1)减值迭代----大多数循环使用一个从0开始、、增加到某个特定值的迭代器,很多情况下,从最大值开始,在循环中不断减值的迭代器更加高效。
(2)简化终止条件----由于每次循环过程都会计算终止条件,所以必须保证他尽可能的快。
(3)简化循环体----循环体是执行的最多的,所以要确保被最大限度的优化,确保没有某些可以被很容易移除循环的密集计算。
(4)使用后测试循环----最常用的for循环和while循环都是前测试循环,而如do-while这种后测试循环,可以避免最初终止条件的计算,因此运行更快。

(当然for和while ,本身功能就有差异的,for语句是计数循环语句,可以非常方便并且准确的控制循环次数。while语句是条件循环语句,适合在循环次数没有明确,只是已知在某个条件下循环需要继续。)

3.展开循环
当循环的次数是确定的,消除循环并使用多次函数调用往往更快。直接对每个元素调用process()语句;
如果循环的迭代次数不能事先确定,那可以考虑使用一种叫做Duff装置的技术,下面的它的优化版:

var iterations = Math.floor(values.length / 8);//商 
var leftover = values.length % 8;  //余数 取值区间[0-7]
var i = 0;
if(leftover > 0){
	do{
		log(values[i++]);
	}while(--leftover > 0);
}
do{
	log(values[i++]);
	log(values[i++]);
	log(values[i++]);
	log(values[i++]);
	log(values[i++]);
	log(values[i++]);
	log(values[i++]);
	log(values[i++]);
}while(--iterations > 0)

function log(val){
	console.log(val);
}

在一个初始化循环中进行除以8的操作。当处理掉额外的元素,继续执行每次调用8次log()的主循环。
4.避免双重解释
当javascript代码想解析javascript的时候就会存在双重解释惩罚,当使用eval()函数或者说是
function()构造函数以及使用setTimeout()传一个字符串参数是都会发生这种情况。下面有一个例子。

// 创建新函数,应该避免
// var sayhi = function ("alert('hello world')");

var sayhi = function(){
	alert("hello world");
}

如果要提高代码性能,尽可能避免出现需要按照JavaScript解释的字符串。
5.性能的其他注意事项
a.原生方法较快
b.Switch语句较快–如果一系列的if-else语句可以转化成单个switch语句则可以得到更快的代码。
c.位运算较快–当进行数学的时候,位运算操作要比任何布尔运算或者算数运算都要快。

三、最小化语句数

1.多个变量声明

/**
* 四个语句很浪费         
*var count = 4;
var color = "red";
var name = "zhangsan";
var now = new Date();
*/
var count = 4 ,
	color = "red",
	values = [1,2,3],
	now = new Date();

2.插入迭代值
当使用迭代值(也就是在不同的位置进行增加或减少的值)的时候,尽可能合并语句。

// 优化下面代码
// var name = values[i];
// i++;
var name = values[i++];

3.使用数值和对象字面量
使用构造函数总是要用到更多的语句来插入元素或者定义属性,而字面量可以将这些操作在一个语句中完成。

/*
// 优化下列代码
var values = new Array();
values[0] = 1;
values[1] = 2;
values[2] = 3;

var person = new Object();
person.name = "zhangsan";
person.age = 18;
person.mark = "eat";
*/
var values = [1,2,3];
var person = {name:"zhangsan",age:18,mark:"eat"};

四、优化DOM交互

DOM操作交互需要消耗大量的时间,因为它们往往需要重新渲染整个界面或者某一部分。进一步说,看似细微的操作也可能要花很久来执行,因为DOM要处理非常多的信息。理解如何优化DOM的交互可以极大的提高脚本完成的速度。
1.最小化现场更新
一旦你需要访问的DOM部分是已经显示的页面的一部分,那么你就是在进行一个现场更新,之所以叫现场更新,是因为需要立即(现场)对用户的显示进行更新,每一个更改,不管是插入单个字符还是移除整个片段都有一个性能惩戒,因为浏览器要重新计算无数尺寸以进行更新。现场更新进行的越多,代码完成执行所花的时间就越长,完成一个操作所需要的现场更新越少代码越快。

/**
	为列表添加10个项目,添加每个项目都有2个现场更新,一共20个现场更新
**/
var list = document.getElementById("list"),
	item,
	i;
for(i = 0;i < 10 ;i++){
	item = document.createElement("li");
	list.appendChild(item);
	item.appendChild(document.createTextNode(i));
}

// 优化后的代码
/* 代码中只有一次现场更新,他发生在所有项目都创建好之后,文档片段用作一个临时的占位符,
放置在新创建的项目,然后使用appendChild()将所有项目添加到列表。
记住,给appendChild()传入文档片段时,只有片段的字节点被添加到目标,片段本身不会被添加。
*/
var list = document.getElementById("list"),
	fragment = document.createDocumentFragment(),
	item,
	i;
for(i = 0;i < 10 ;i++){
	item = document.createElement("li");
	Fragment.appendChild(item);
	item.appendChild(document.createTextNode(i));
}
list.appendChild(fragment);

结论:一旦需要更新DOM,请考虑使用文档片段来构建DOM结构,然后添加到现存的文档。
2.使用innerHTML
对于小的DOM更改,createElement()、appendChild()之类的DOM方法和innerHTML(),两种方法效率都差不多。对于大的DOM更改,使用innerHTML要比使用标准DOM方法创建同样的DOM结构要快得多。

var list = document.getElementById("mylist"),
	html,
	i;
for(i = 0;i < 10 ;i++){
	html += "<li>" + i +"</li>";
}
list.innerHTML = html;

构建好一个字符串然后一次性调用innerHTML要比调用innerHTML多次快得多。
3.使用事件代理
事件代理,用到了事件冒泡。任何可以冒泡的事件都不仅仅可以在事件目标上进行处理,目标的任何祖先节点上也能处理。使用这个知识,就可以将事件处理程序附加到更高层的地方负责多个目标的事件处理。

// DOM结构 ul#mylist>li{Header $}*5

// 点击li输出其中的text
    var list = document.getElementById("mylist");
    list.onclick = function (event) {
        event = event || window.event;
        // 验证是否为li,不是li不进行操作
        if(event.target.nodeName.toLowerCase() == 'li'){
            console.log(event.target.innerText);
         }
    }

4.注意HTMLCollection
记住,任何时候要访问HTMLCollection,不管他是一个属性还是一个方法,都是在文档上进行一个查询,这个查询很浪费资源,最小化访问HTMLCollection的次数是可以极大地改进脚本的性能。比如循环。

/**
var array = document.getElementsByTagName("img"),
	i;
for(i = 0 ; i < array.length; i++){
	//处理
}
*/
var array = document.getElementsByTagName("img"),
	iamge,i,len;
for(i = 0 ,len = array.length; i < len; i++){
	image = array[i];
	//处理
}

这里的关键在于长度length存入了len的变量,而不是每一次都去访问HTMLCollection的length属性。
编写JavaScript的时候,一定要知道何时返回HTMLCollection对象,这样你就可以最小化对她们的访问。发生以下情况会返回HTMLCollection对象。
a.进行了对getElementsByTagName()的调用;
b.获取了元素的childNodes属性;
c.获取了元素的attributes属性;
d.访问了特殊的集合,如document.forms、document.images等;
-------------------------------------------------------------------over-------------------------------------------------------------
这是我的一点总结,要是有误,我会持续修改。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值