Traffic Light
- Red
- Yellow
- Green
現在jquery應用的越來(lái)越多(duō), 有(yǒu)些(xiē)同學在享受爽快淋漓coding時(shí)就将性能問題忽略了, 比如我. jquery雖在諸多(duō)的js類庫中性能表現還(hái)算(suàn)優秀, 但(dàn)畢竟不是在用原生(shēng)的javascript開(kāi)發, 性能問題還(hái)是需要引起重視(shì)的. 在twitter上(shàng)發現了<jQuery Performance Rules>這篇文章, 簡單的摘譯了一下:
在jquery中最快的選擇器(qì)是ID選擇器(qì). 因為(wèi)它直接來(lái)自于Javascript的getElementById()方法.
Traffic Light
- Red
- Yellow
- Green
像這樣選擇按鈕是低(dī)效的:
var traffic_button = $("#content .button");
用ID直接選擇按鈕效率更高(gāo):
var traffic_button = $("#traffic_button");
選擇多(duō)個(gè)元素
提到多(duō)元素選擇其實是在說DOM遍曆和(hé)循環, 這些(xiē)都是比較慢的東西.為(wèi)了提高(gāo)性能, 最好從就近的ID開(kāi)始繼承.
var traffic_lights = $("#traffic_light input");
第二快的選擇器(qì)是tag選擇器(qì)($(‘head’)). 同理(lǐ),因為(wèi)它來(lái)自原生(shēng)的getElementsByTagName() 方法.
總是用一個(gè)tag name來(lái)限制(zhì)(修飾)class (并且不要忘記就近的ID):
var active_light = $("#traffic_light input.on");
注意: 在jquery中Class是最慢的選擇器(qì). IE浏覽器(qì)下它會(huì)遍曆所有(yǒu)DOM節點不管它用在那(nà)裏.
不要用用tag name來(lái)修飾ID. 下面的例子将會(huì)遍曆所有(yǒu)的div元素來(lái)查找id為(wèi)’content’的哪一個(gè)節點:
var content = $("div#content");
用ID修飾ID也是畫(huà)蛇添足:
var traffic_light = $("#content #traffic_light");
要養成将jquery對象緩存進變量的習慣.
永遠不要這樣做(zuò):
$("#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");
最好先将對象緩存進一個(gè)變量然後再操作(zuò):
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");
為(wèi)了記住我們本地變量是jquery的封裝, 通(tōng)常用一個(gè)$作(zuò)為(wèi)變量前綴. 記住,永遠不要讓相同的選擇器(qì)在你(nǐ)的代碼裏出現多(duō)次.
緩存jquery結果,備用
如果你(nǐ)打算(suàn)将jquery結果對象用在程序的其它部分,或者你(nǐ)的function會(huì)多(duō)次執行(xíng), 那(nà)麽就将他們緩存到一個(gè)全局變量中.
定義一個(gè)全局容器(qì)來(lái)存放jquery結果, 我們就可(kě)以在其它函數(shù)引用它們:
// 在全局範圍定義一個(gè)對象 (例如: window對象) window.$my = { // 初始化所有(yǒu)可(kě)能會(huì)不止一次要使用的查詢 head : $("head"), traffic_light : $("#traffic_light"), traffic_button : $("#traffic_button") }; function do_something() { // 現在你(nǐ)可(kě)以引用存儲的結果并操作(zuò)它們 var script = document.createElement("script"); $my.head.append(script); // 當你(nǐ)在函數(shù)內(nèi)部操作(zuò)是, 可(kě)以繼續将查詢存入全局對象中去. $my.cool_results = $("#some_ul li"); $my.other_results = $("#some_table td"); // 将全局函數(shù)作(zuò)為(wèi)一個(gè)普通(tōng)的jquery對象去使用. $my.other_results.css("border-color", "red"); $my.traffic_light.css("border-color", "green"); }
上(shàng)面的例子也可(kě)以寫成這樣:
var $active_light = $("#traffic_light input.on");$active_light.bind("click", function(){…}) .css("border", "3px dashed yellow") .css("background-color", "orange") .fadeIn("slow");
這樣可(kě)以寫更少(shǎo)的代碼, 讓我們的js更輕量.
jQuery 允許我們對一個(gè)已包裝的對象使用附加的選擇器(qì)操作(zuò). 因為(wèi)我們已經在保存了一個(gè)父級對象在變量裏, 這樣大(dà)大(dà)提高(gāo)對其子元素的操作(zuò):
例如, 我們可(kě)以用子查詢的方法來(lái)抓取到亮或不亮的燈, 并緩存起來(lái)以備後續操作(zuò).
var $traffic_light = $("#traffic_light"), $active_light = $traffic_light.find("input.on"), $inactive_lights = $traffic_light.find("input.off");
提示: 你(nǐ)可(kě)以用逗号分隔的方法一次聲明(míng)多(duō)個(gè)局部變量–節省字節數(shù)
這裏的基本思想是在內(nèi)存中建立你(nǐ)确實想要的東西,然後更新DOM 。這并不是一個(gè)jQuery最佳實踐,但(dàn)必須進行(xíng)有(yǒu)效的JavaScript操作(zuò) 。直接的DOM操作(zuò)速度很(hěn)慢。
例如,你(nǐ)想動态的創建一組列表元素, 千萬不要這麽做(zuò):
var top_100_list = [...], // 假設這裏是100個(gè)獨一無二的字符串 $mylist = $("#mylist"); // jQuery 選擇到
我們應該将整套元素字符串在插入進dom中之前全部創建好:
var top_100_list = [...], $mylist = $("#mylist"); top_100_li = ""; // 這個(gè)變量将用來(lái)存儲我們的列表元素 for (var i=0, l=top_100_list.length; i
我們在插入之前将多(duō)個(gè)元素包裹進一個(gè)單獨的父級節點會(huì)更快:
var top_100_list = [...], $mylist = $("#mylist"), top_100_ul = "
如果你(nǐ)做(zuò)了以上(shàng)幾條還(hái)是擔心有(yǒu)性能問題,那(nà)麽:
試試jquery的 clone() 方法, 它會(huì)創建一個(gè)節點樹(shù)的副本, 它允許以”離線”的方式進行(xíng)dom操作(zuò), 當你(nǐ)操作(zuò)完成後再将其放回到節點樹(shù)裏. 使用DOM DocumentFragments. 正如jQuery作(zuò)者所言, 它的性能要明(míng)顯優于直接的dom操作(zuò).
除非在特殊情況下, 否則每一個(gè)js事件(例如:click, mouseover, 等.)都會(huì)冒泡到父級節點. 當我們需要給多(duō)個(gè)元素調用同個(gè)函數(shù)時(shí)這點會(huì)很(hěn)有(yǒu)用.
代替這種效率很(hěn)差的多(duō)元素事件監聽(tīng)的方法就是, 你(nǐ)隻需向它們的父節點綁定一次, 并且可(kě)以計(jì)算(suàn)出哪個(gè)節點觸發了事件.
例如, 我們要為(wèi)一個(gè)擁有(yǒu)很(hěn)多(duō)輸入框的表單綁定這樣的行(xíng)為(wèi): 當輸入框被選中時(shí)為(wèi)它添加一個(gè)class
像這樣綁定事件是低(dī)效的:
$("#entryform input).bind("focus", function(){ $(this).addClass("selected"); }).bind("blur", function(){ $(this).removeClass("selected"); });
我們需要在父級監聽(tīng)獲取焦點和(hé)失去焦點的事件:
$("#entryform").bind("focus", function(e){ var cell = $(e.target); // e.target grabs the node that triggered the event. cell.addClass("selected"); }).bind("blur", function(e){ var cell = $(e.target); cell.removeClass("selected"); });
父級元素扮演了一個(gè)調度員的角色, 它可(kě)以基于目标元素綁定事件. 如果你(nǐ)發現你(nǐ)給很(hěn)多(duō)元素綁定了同一個(gè)事件監聽(tīng), 那(nà)麽你(nǐ)肯定哪裏做(zuò)錯了.
盡管jquery可(kě)以很(hěn)優雅的處理(lǐ)沒有(yǒu)匹配元素的情況, 但(dàn)它還(hái)是需要花(huā)費時(shí)間(jiān)去尋找. 如果你(nǐ)整站(zhàn)隻有(yǒu)一個(gè)全局js, 那(nà)麽極有(yǒu)可(kě)能把所有(yǒu)的jquery函數(shù)塞進$(document)ready(function(){//所有(yǒu)你(nǐ)引以為(wèi)傲的代碼})裏.
隻運行(xíng)在頁面裏用到的函數(shù). 大(dà)多(duō)數(shù)有(yǒu)效的方法就是使用行(xíng)內(nèi)初始化函數(shù), 這樣你(nǐ)的模闆就能準确的控制(zhì)何時(shí)何處該執行(xíng)js.
例如, 你(nǐ)的”文章”頁面模闆, 你(nǐ)可(kě)能會(huì)引用如下的代碼在body結束處:
如果你(nǐ)的頁面模闆包含一些(xiē)多(duō)變的模塊可(kě)能不會(huì)出現在頁面中, 或者為(wèi)了視(shì)覺呈現的原因你(nǐ)需要它們能夠快速加載, 你(nǐ)可(kě)以将初始化函數(shù)緊跟在模塊之後.
你(nǐ)的全局js庫可(kě)能會(huì)是這樣子的:
var mylib = { article_page : { init : function() { // Article 特有(yǒu)的jQuery函數(shù). } }, traffic_light : { init : function() { // Traffic light 特有(yǒu)的jQuery函數(shù). } } }
jquery對于開(kāi)發者來(lái)說有(yǒu)一個(gè)很(hěn)誘人(rén)的東西, 可(kě)以把任何東西挂到$(document).ready下冒充事件. 在大(dà)多(duō)數(shù)例子中你(nǐ)都會(huì)發現這樣的情況.
盡管$(document).rady 确實很(hěn)有(yǒu)用, 它可(kě)以在頁面渲染時(shí),其它元素還(hái)沒下載完成就執行(xíng). 如果你(nǐ)發現你(nǐ)的頁面一直是載入中的狀态, 很(hěn)有(yǒu)可(kě)能就是$(document).ready函數(shù)引起的.
你(nǐ)可(kě)以通(tōng)過将jquery函數(shù)綁定到$(window).load 事件的方法來(lái)減少(shǎo)頁面載入時(shí)的cpu使用率. 它會(huì)在所有(yǒu)的html(包括
$(window).load(function(){ // 頁面完全載入後才初始化的jQuery函數(shù). });
多(duō)餘的功能例如拖放, 視(shì)覺特效和(hé)動畫(huà), 預載入隐藏圖像,等等. 都是适合這種技(jì)術(shù)的場(chǎng)合.
推薦一個(gè)js在線壓縮地址: http://dean.edwards.name/packer/
知己知彼, 百戰百勝. 隻有(yǒu)更深入的了解jQuery才能更靈活的使用它. 這裏提供一個(gè)jQuery的速查手冊, 可(kě)以打印出來(lái)随身攜帶. 要是有(yǒu)能力将jQuery源碼通(tōng)讀一遍那(nà)就更好了.
本文摘自:http://rlog.cn,英文原文:http://www.artzstudio.com/2009/04/jquery-performance-rules/