之前,我們減少位元組數和請求次數以及載入順序以使頁面載入的更快。如今,我們越來越多的注意到另一個影響網站效能的部分--CPU利用率。使用
jQuery和其他JavaScript架構,使節點選擇和DOM操作變得越來越容易,如果使用不當,有可能影響整個網頁的響應速度,下面列舉11個更有
效的使用jQuery庫:
1、總是使用#id去尋找element.
在jQuery中最快的選取器是ID選取器 ($('#someid')). 這是因為它直接映射為JavaScript的getElementById()方法。
選擇單個元素
<div id="content">
<form method="post" action="/">
<h2>Traffic Light</h2>
<ul id="traffic_light">
<li><input type="radio" class="on" name="light" value="red" /> Red</li>
<li><input type="radio" class="off" name="light" value="yellow" /> Yellow</li>
<li><input type="radio" class="off" name="light" value="green" /> Green</li>
</ul>
<input class="button" id="traffic_button" type="submit" value="Go" />
</form>
</div>
選擇button的效能不好的一種方式:
var traffic_button = $('#content .button');
取而代之的是直接選擇button:
var traffic_button = $('#traffic_button');
選擇多個元素
在我們討論選擇多個元素的時候,我們真正需要知道的是DOM的遍曆和迴圈才是效能低下的原因。為了盡量減少效能損失, 總是使用最近的父ID去尋找。
var traffic_lights = $('#traffic_light input');
2、在Classes前面使用Tags
在jQuery中第二快的選取器就是Tag選取器 ($('head')). 而這是因為它直接映射到JavaScript的getElementsByTagName()方法。
<div id="content">
<form method="post" action="/">
<h2>Traffic Light</h2>
<ul id="traffic_light">
<li><input type="radio" class="on" name="light" value="red" /> Red</li>
<li><input type="radio" class="off" name="light" value="yellow" /> Yellow</li>
<li><input type="radio" class="off" name="light" value="green" /> Green</li>
</ul>
<input class="button" id="traffic_button" type="submit" value="Go" />
</form>
</div>
總是在一個Class前面加上一個tag名字(記得從一個ID傳下來)
var active_light = $('#traffic_light input.on');
注意:在jQuery裡Class選取器是最慢的一個選取器;在IE中它迴圈整個DOM。可能的話盡量避免使用它。不要在ID前面
加Tags。例如,它會因為去迴圈所有的<div>元素去尋找ID為content的<div>,而導致很慢。
var content = $('div#content');
按照同樣的思路,從多個ID傳下來是冗餘的。
var traffic_light = $('#content #traffic_light');
3、緩衝jQuery對象
養成儲存jQuery對象到一個變數上(就像上面的例子)的習慣。例如,不要這樣做:
$('#traffic_light input.on).bind('click', function(){...});
$('#traffic_light input.on).css('border', '3px dashed yellow');
$('#traffic_light input.on).css('background-color', 'orange');
$('#traffic_light input.on).fadeIn('slow');
取而代之,首現儲存jQuery變數到一個本地變數後,再繼續你的操作。
var $active_light = $('#traffic_light input.on');$active_light.bind('click', function(){...});$active_light.css('border', '3px dashed yellow');$active_light.css('background-color', 'orange');$active_light.fadeIn('slow');
提示:使用$前輟表示我們的本地變數是一個jQuery包集。記住,不要在你的應該程式裡出現一次以上的jQuery重複的選擇操作。 額外提示:延遲儲存jQuery對象結果。
如果你想在你的程式的其它地方使用jQuery結果對象(result object(s)),或者你的函數要執行多次,要把它緩衝在一個全域範圍的對象裡。通過定義一個全域容器儲存jQuery結果對象,就可以在其它的函數裡引用它。
// Define an object in the global scope (i.e. the window object)
window.$my ={
// Initialize all the queries you want to use more than once
head : $('head'),
traffic_light : $('#traffic_light'),
traffic_button : $('#traffic_button')};
function do_something(){
// Now you can reference the stored results and manipulate them
var script = document.createElement('script');
$my.head.append(script);
// When working inside functions, continue to save jQuery results
// to your global container.
$my.cool_results = $('#some_ul li');
$my.other_results = $('#some_table td');
// Use the global functions as you would a normal jQuery result
$my.other_results.css('border-color', 'red');
$my.traffic_light.css('border-color', 'green');
}
4、更好的利用鏈
前面的例子也可以這樣寫:
var $active_light = $('#traffic_light input.on');
$active_light.bind('click', function(){...})
.css('border', '3px dashed yellow')
.css('background-color', 'orange')
.fadeIn('slow');
這樣可以讓我們寫更少的代碼,使JavaScript更輕量。
5、使用子查詢
jQuery允許我們在一個包集上附加其它的選取器。因為我們已經在本地變數裡儲存了父物件這樣會減少以後在選取器上的效能開銷。
<div id="content">
<form method="post" action="/">
<h2>Traffic Light</h2>
<ul id="traffic_light">
<li><input type="radio" class="on" name="light" value="red" /> Red</li>
<li><input type="radio" class="off" name="light" value="yellow" /> Yellow</li>
<li><input type="radio" class="off" name="light" value="green" /> Green</li>
</ul>
<input class="button" id="traffic_button" type="submit" value="Go" />
</form>
</div>
例如,我們可以利用子查詢緩衝active和inactive lights以便後面的操作。
var $traffic_light = $('#traffic_light'),
$active_light = $traffic_light.find('input.on'),
$inactive_lights = $traffic_light.find('input.off');
提示:可以用逗號隔開一次定義多個本地變數,這樣可以節省一些位元組。
6、限制直接對DOM操作
DOM操作的基本做法是在記憶體中建立DOM結構,然後再更新DOM結構。這不是jQuery最好的做法,但對JavaScript來講是高效的。直接操作DOM結構效能是低下的。 例如,如果你需要動態建立一列元素,不要這樣做:
var top_100_list = [...], // assume this has 100 unique strings
$mylist = $('#mylist'); // jQuery selects our <ul> element
for (var i=0, l=top_100_list.length; i<l; i++){
$mylist.append('<li>' + top_100_list[i] + '</li>');
}
取而代之,我們希望在插入DOM結構之前先在一個字串裡建立一套元素。
代碼
var top_100_list = [...], // assume this has 100 unique strings
$mylist = $('#mylist'), // jQuery selects our <ul> element
top_100_li = ""; // This will store our list items
for (var i=0, l=top_100_list.length; i<l; i++){
top_100_li += '<li>' + top_100_list[i] + '</li>';
}
$mylist.html(top_100_li);
更快的做法,在插入DOM結構之前我們應該總是在一個父節點裡包含許多元素
var top_100_list = [...], // assume this has 100 unique strings
$mylist = $('#mylist'), // jQuery selects our <ul> element
top_100_ul = '<ul id="#mylist">'; // This will store our entire unordered list
for (var i=0, l=top_100_list.length; i<l; i++){
top_100_ul += '<li>' + top_100_list[i] + '</li>';
}
top_100_ul += '</ul>'; // Close our unordered list
$mylist.replaceWith(top_100_ul);
如是你照著上面的做了還是對效能有些迷惑的話,可以參考以下內容:
* 試一下jQuery提供的Clone()方法。Clone()方法建立節點數的拷貝,隨後你可以在這個副本中進行操作。
* 使用DOM DocumentFragments. As the creator of jQuery points out,
比直接操作DOM效能上更好. 先建立你需要的結構(就像我們上面用一個字串做的一樣), 然後使用jQuery的 insert or
replace methods.
7、事件委託(又名:冒泡事件)
除 非特別說明,每一個JavaScript事件(如click, mouseover
等)在DOM結構樹上都會冒泡到它的父元素上。如果我們想讓很多elements(nodes)調用同一個function這是非常有用的。取而代之的是
你可以只對它們的父級綁定一次,而且可以計算出是哪一個節點觸發了事件,而不是綁定一個事件監聽器到很多節點上這種效率低下的方式。例如,假如我們要開發
一個包含很多input的大型form,當input被選擇的時候我們想綁定一個class name。像這樣的幫定是效率低下的:
$('#myList li).bind('click', function(){
$(this).addClass('clicked'); // do stuff
});
反而,我們應該在父級偵聽click事件。
$('#myList).bind('click', function(e){
var target = e.target, // e.target grabs the node that triggered the event.
$target = $(target); // wraps the node in a jQuery object
if (target.nodeName === 'LI') {
$target.addClass('clicked'); // do stuff
}
});
父節點擔當著發報機的工作,可以在觸發了事件的目標element上做一些工作。如果你發現自己把一個event listener幫定到很多個element上,那麼你這種做法是不正確的。
8、消除查詢浪費
雖
然jQuery對沒有找到任何匹配的elements處理的很好,但是它還是需要花費時間去尋找的。如果你的網站有一個全域的JavaScript,你可
能會把每個jQuery function都放在 $(document).ready(function(){ // all my
glorious code })裡。
不要這樣做。只去放一些頁面上適合用到的function。這樣做最有效方式是你的模板可以完全控制任何時候或者地方執行JavaScript以內聯腳
本的方式初始化function。例如,在你的“article”頁面模板裡,你可能在body標籤關閉之前包含以下代碼
<script
type="text/javascript>mylib.article.init();</script></body&
gt;如果你的頁面模板包含多種有可能在頁面或者不在頁面上的模組,或者為了視覺效果你需要它們稍後再初如化,你應該在這些模組之後立即放置初如化函
數。
<ul id="traffic_light">
<li><input type="radio" class="on" name="light" value="red" /> Red</li>
<li><input type="radio" class="off" name="light" value="yellow" /> Yellow</li>
<li><input type="radio" class="off" name="light" value="green" /> Green</li>
</ul>
<script type="text/javascript>mylib.traffic_light.init();</script>
你的全域JavaScript庫看起來應該是這樣的:
var mylib ={
article_page : {
init : function() {
// Article page specific jQuery functions.
}
},
traffic_light : {
init : function() {
// Traffic light specific jQuery functions.
}
}
}
9、遵從$(windows).load
有 一種誘惑會使jQuery開發人員hook所有事情到 $(document).ready
這個虛偽的事件裡。畢竟在大多數例子裡都可以看到這樣使用。雖然$(document).ready
非常有用,它在頁面呈現時發生,雖然其它對象還在下載中。如果你發現你的頁面在下載中停頓,就有可能是$(document).ready
引起的。你可以通過把jQuery
functions幫定到$(window).load事件來減少下面下載時的CPU使用率,它是在所有HTML(包括iframe內容)都下載完以後才
去調用所有對象的。
$(window).load(function(){
// jQuery functions to initialize after the page has loaded.
});
多餘的功能,如拖拽、幫定視覺效果和動畫、預讀取圖片等,使用這種方法比較好。
10、壓縮JS
雖然和jQuery無關,但在這裡也要提一下。使JavaScript函數和變數變得可讀是一個趨勢,這對開發人員來講是必不可少的,但對普通使用者來
講沒有任何關係。不用什麼借口,是時候把JS壓縮納入我們的工作流程中來了。注釋你的代碼,在投放到生產環境之前找一個壓縮公用程式進行壓縮。使用
YUICompressor
壓縮你代碼中多餘的浪費的位元組。根據我們的經驗,它可以安全的把JavaScript壓縮的儘可能小,而不會多佔用CPU。小提示:為了在
YUICompressor裡最大化壓縮,應該這樣這樣定義變數(例如:var my_long_variable_name;)
11、學習jQuery API庫文檔
學習和最有效使用jQuery,最好的方法就是去查jQuery的文檔了,可以當作手冊來用。