Libraries: Performance vs. Native JS,librariesnative
原文連結: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是一種更快的選擇,但是把學會封裝,以物件導向的思維來編程可以讓寫代碼的過程更高效。我們應該注意,當我們能自己的方式來完成一個目標時,是否應該使用一個很大的第三方程式碼程式庫還完成。第三方程式碼程式庫可能會讓你開發核心產品時更加容易,但要注意它們可能也會影響效能。