原文链接:http://codepen.io/doughensel/blog/10-libraries
假设:
当我们把代码抽取到一个可重复调用的块中时,它会阻碍代码的性能。除了使用原生DOM元素。一个JS库总是强迫浏览器查找到某块代码的引用来执行它本来应该执行的动作,就是说JS库总是以引用对象来执行动作。
为了这个性能比较,我用几种不同的代码运行了一个快速性能测试,并记录了其结果的变化。
说明:
使用的工具:
硬件:MacBook Pro : OS X
浏览器:Google Chrome,Safari,FireFox
代码/测试场景
window.onload = function(){
var counter = 0;
var timerAverage = 0;
function runTest(){
var timerEnd;
var timer = new Date();
for(var i=0,x=99999; i<=x; i++){
/**test case**/
}
timerEnd = new Date() - timer;
console.log(timerEnd + ‘ms‘);
counter++;
timerAverage
+= timerEnd;
if(counter < 100){
runTest();
} else{
console.log(‘average time: ‘+(timerAverage/counter)+‘ms‘);
}
}
//执行测试函数
runTest();
}
快速浏览一下这个基础测试代码:
window.onload事件会在所有DOM都被加载完成后触发。
runTest()函数就是追踪运行时间和执行遍历的代码块。
测试场景1:
原生JavaScript
window.onload = function(){
var counter = 0;
var timerAverage = 0;
function runTest(){
var timerEnd;
var timer = new Date();
for(var i=0,x=99999; i<=x; i++){
/**test case**/
document.getElementById(‘id‘).style.color = ‘blue‘;
}
timerEnd = new Date() - timer;
console.log(timerEnd + ‘ms‘);
counter++;
timerAverage += timerEnd;
if(counter < 100){
runTest();
} else{
console.log(‘average time: ‘+(timerAverage/counter)+‘ms‘);
}
}
//执行测试函数
runTest();
}
测试场景2:函数表达式编程Functional Programming
在这个测试场景中,我们会创造一个函数,根据传入的字符串id返回document.getElementById(‘id‘)得到的DOM元素。
var $ = function(elem){
return document.getElementById(elem);
};
这个函数表达式的额外好处就是程序员不是每次都输入‘getElementById‘,当他们需要得到某个元素的引用时。只需使用该函数表达式就可以。
$(‘id‘).style.color = ‘blue‘;
测试代码:
var $ = function(elem){
return document.getElementById(elem);
};
window.onload = function(){
var counter = 0;
var timerAverage = 0;
function runTest(){
var timerEnd;
var timer = new Date();
for(var i=0,x=99999; i<=x; i++){
/**test case**/
$(‘id‘).style.color = ‘blue‘;
}
timerEnd = new Date() - timer;
console.log(timerEnd + ‘ms‘);
counter++;
timerAverage += timerEnd;
if(counter < 100){
runTest();
} else{
console.log(‘average time: ‘+(timerAverage/counter)+‘ms‘);
}
}
//执行测试函数
runTest();
}
测试场景3:面向对象的编程,Object Orientated Programming
在这个场景中,我们先创造一个可以被扩展的对象。当第一次调用下面代码时,会初始化一个新的对象,然后我们把DOM元素作为该对象的‘el‘属性的值。
(function(){
var $ = function(elem){
if(!(this instanceof $)){
return new $(elem);
}
this.el = document.getElementById(elem);
};
window.$ = $;
}) ();
这个测试场景中方法的调用很像函数表达式中方法的调用,只是多了‘.el‘。
$(‘id‘).el.style.color = ‘blue‘;
测试代码:
(function(){
var $ = function(elem){
if(!(this instanceof $)){
return new $(elem);
}
this.el = document.getElementById(elem);
};
window.$ = $;
})();
window.onload = function(){
var counter = 0;
var timerAverage = 0;
function runTest(){
var timerEnd;
var timer = new Date();
for(var i=0,x=99999; i<=x; i++){
/**test case**/
$(‘id‘).el.style.color = ‘blue‘;
}
timerEnd = new Date() - timer;
console.log(timerEnd + ‘ms‘);
counter++;
timerAverage += timerEnd;
if(counter < 100){
runTest();
} else{
console.log(‘average time: ‘+(timerAverage/counter)+‘ms‘);
}
}
//执行测试函数
runTest();
}
测试场景四:使用jQuery。jQuery文件已被保存到本地文件,以避免从服务器下载jQuery文件时产生的任何潜在的延时。
测试代码:
window.onload = function(){
var counter = 0;
var timerAverage = 0;
function runTest(){
var timerEnd;
var timer = new Date();
for(var i=0,x=99999; i<=x; i++){
/**test case**/
$(‘#id‘).css(‘background-color‘,‘blue‘);
}
timerEnd = new Date() - timer;
console.log(timerEnd + ‘ms‘);
counter++;
timerAverage += timerEnd;
if(counter < 100){
runTest();
} else{
console.log(‘average time: ‘+(timerAverage/counter)+‘ms‘);
}
}
//执行测试函数
runTest();
}
测试结果:
场景1:
场景2:
场景3:
场景4:
原生JS性能最好,函数表达式和面向对象的函数次之,jQuery最后。
但是,在前三个测试场景中,div都没有变为蓝色,只有jQuery让div元素变色了。原因可能是浏览器的js执行引擎和ui渲染引擎是互斥运行的,js代码在执行时是不会渲染界面的,jQuery可能在这方面做了优化。偶也不是很懂,还请大牛指导。
结论:
原生JS执行速度最快,函数表达式和面向对象编程的方法的执行效率很接近原生JS。
诚然,jQuery从一开始就注定了其结果。因为在其他的测试场景中,只有很少一块代码被使用,jQuery则是使用了整个jQuery库。除了DOM节点的选择,jQuery还使用了jQuery的css方法来更改元素样式,这都增加了很多额外的工作。
此外,我们还了解到,最短的、可执行的代码是效率最高的。尽管原生的js是一种更快的选择,但是把学会封装,以面向对象的思维来编程可以让写代码的过程更高效。
我们应该注意,当我们能自己的方式来完成一个目标时,是否应该使用一个很大的第三方代码库还完成。第三方代码库可能会让你开发核心产品时更加容易,但要注意它们可能也会影响性能。