阅读了博客园发布的IT文章《30个提高Web程序执行效率的好经验》,这30条准则对我们web开发是非常有用的,不过大家可能对其中的一些准则是知其然而不知其所以然。
下面是我对这些准则的理解和分析,有些有关JS性能的准则,我也测试了它们的差异,大家可以下载DEMO页面,如有理解不正确的地方,请大家指正。也非常欢迎大家补充。
测试环境:
OS:Vista;
Processor:3.40GHz;
Memory: 2.00GB;
System type: 32-bit Operating System;
Browser: IE8, Forefox 3.5.7, Chrome4.0.249
1. 尽量避免使用DOM。当需要反复使用DOM时,先把对DOM的引用存到JavaScript本地变量里再使用。使用设置innerHTML的方法来替换document.createElement/appendChild()方 法。
我们可以用如下的代码进行测试:
function testInnerHTML(){
var div1 = document.getElementById("testDiv");
var startTime = new Date();
var buf = new Array();
for (var n = 0; n < 5000; n ++){
buf.push('<a href="">test');
buf.push(n);
buf.push('</a>');
}
div1.innerHTML = buf.join('');
document.getElementById('divShowTime1').innerHTML = '耗时1:' + (new Date() - startTime) + 'ms';
div1.innerHTML = "";
}
function testCreateElement(){
var div1 = document.getElementById("testDiv");
var startTime = new Date();
for (var n = 0; n < 5000; n ++){
var e = document.createElement('a');
e.href = '';
e.innerText = 'test' + n;
div1.appendChild(e);
}
document.getElementById('divShowTime2').innerHTML = '耗时2:' + (new Date() - startTime) + 'ms';
div1.innerHTML = "";
}
测试结果:
| IE8 | Firefox | Chrome |
1 | 耗时1:134ms | 耗时1:570ms | 耗时1:61ms |
2 | 耗时1:131ms | 耗时1:474ms | 耗时1:58ms |
3 | 耗时1:131ms | 耗时1:673ms | 耗时1:57ms |
4 | 耗时1:132ms | 耗时1:540ms | 耗时1:55ms |
测试结果显示使用innerHTML对比document.createElement/appendChild()方法,在IE8中,效率的提高是非常明显的,但是在Firefox和Chrome中,差别不大。
2. eval()有问题,new Fuction()构造函数也是,尽量避免使用它们。
eval方式比直接调用方式多了一步解析的过程,所以尽量避免使用它,如果必须用它,则最好是把调用的代码包装到函数中,然后eval这个函数,这样减少了解析的时间。eval函数的效率,我们可以用如下的代码测试:
function testNoEval() {
var startTime = new Date();
for(var i=0; i<500000; i++) {
var str = 'test';
}
var endTime = new Date();
document.getElementById('divShowTime1').innerHTML = '耗时1:' + (endTime - startTime) + 'ms';
}
function testEval() {
var startTime = new Date();
eval("for(var i=0; i<500000; i++) { var str = 'test'; }");
var endTime = new Date();
document.getElementById('divShowTime2').innerHTML = '耗时2:' + (endTime - startTime) + 'ms';
}
测试结果:
| IE8 | Firefox | Chrome |
1 | 耗时1:85ms | 耗时1:2ms | 耗时1:1ms |
2 | 耗时1:82ms | 耗时1:2ms | 耗时1:2ms |
3 | 耗时1:81ms | 耗时1:2ms | 耗时1:1ms |
4 | 耗时1:82ms | 耗时1:2ms | 耗时1:2ms |
测试发现,eval的效率明显慢很多,尤其在Firefox和chrome中。 new Fuction的执行原理和eval类似,所以效率也是不高。
3. 拒绝使用with语句。 它会导致当你引用这个变量时去额外的搜索这样的一个命名空间,with里的代码在编译时期是完全未知的。
原因明确,不过使用with语句,代码会非常简洁,我个人还是经常使用这个语句的。
4. 使用for()循环替代for…in循 环。因为for…in循环在开始循环之前需要Script引擎创建一个含有所有可循环属性的 List,需要多检查一次。
原因明确,没有补充。
5. 把try-catch语句放在循环外面,不要放在循环里面,因为异常是很少发生的,放在外面避免每次都要执行 它们。
原因明确,这是我认为使用任何语言都有必要遵守的准则。
6. 甚至圣经里都提到过这个 – 不要全局的。全局变量的生命周期贯穿整个脚本的生命周期,而本地变量的存在范围随着本地命名空间的销毁而消失。当在函数或其它地方引用一个全局变量时,脚 本引擎需要搜索整个全局命名空间。
防止内存泄漏和提高查找解析速度,另外,变量定义在最小使用范围内,代码的可读性好。
7. fullName += 'John'; fullName += 'Holdings';执行速度快于fullName += 'John' + 'Holdings';
还是采用测试代码:
function testString1() {
var startTime = new Date();
for(var i=0; i<500000; i++) {
var fullName = "";
fullName += 'John';
fullName += 'Holdings';
}
var endTime = new Date();
document.getElementById('divShowTime1').innerHTML = '耗时1:' + (endTime - startTime) + 'ms';
}
function testString2() {
var startTime = new Date();
for(var i=0; i<500000; i++) {
var fullName = "";
fullName += 'John' + 'Holdings';
}
var endTime = new Date();
document.getElementById('divShowTime2').innerHTML = '耗时2:' + (endTime - startTime) + 'ms';
}
测试结果:
| IE8 | Firefox | Chrome |
1 | 耗时1:492ms | 耗时1:151ms | 耗时1:52ms |
2 | 耗时1:532ms | 耗时1:150ms | 耗时1:50ms |
3 | 耗时1:493ms | 耗时1:148ms | 耗时1:53ms |
4 | 耗时1:491ms | 耗时1:204ms | 耗时1:51ms |
测试结果出乎意料,在IE8和chrome中,两者的效率差不多,但是在Firefox中,第一种写法反而比第二种慢很多。IE6下测试也是如此,看来这条规则还有待进一步研究。
8. 如果你需要把多个字符串连接起来,最好是把他们做成一个数组,然后调用join()方法实现这个操作。这种方式在生成HTML片段时尤其 有效。
验证还是用测试代码:
function testNoJoin(){
var startTime = new Date();
var testStr = "abcdefghqwertyuiolkjmzxv";
var result = "";
for(var i=0; i<50000; i++) result += testStr;
document.getElementById('divShowTime1').innerHTML = '耗时1:' + (new Date() - startTime) + 'ms';
}
function testJoin(){
var startTime = new Date();
var testStr = "abcdefghqwertyuiolkjmzxv";
var result = "";
var strs = new Array();
for(var i=0; i<50000; i++) strs[i] = testStr;
result = strs.join("");
document.getElementById('divShowTime2').innerHTML = '耗时2:' + (new Date() - startTime) + 'ms';
strs = null;
}
测试结果:
| IE8 |