RELATEED CONSULTING
相關咨詢
選擇下列産品馬上(shàng)在線溝通(tōng)
服務時(shí)間(jiān):9:00-18:00
你(nǐ)可(kě)能遇到了下面的問題
關閉右側工具欄
jQuery性能優化指南
  • 作(zuò)者:admin
  • 發表時(shí)間(jiān):2013-07-02 14:17:23
  • 來(lái)源:未知

現在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>這篇文章, 簡單的摘譯了一下:

  • 總是從ID選擇器(qì)開(kāi)始繼承
  • 在class前使用tag
  • 将jquery對象緩存起來(lái)
  • 掌握強大(dà)的鏈式操作(zuò)
  • 使用子查詢
  • 對直接的DOM操作(zuò)進行(xíng)限制(zhì)
  • 冒泡
  • 消除無效查詢
  • 推遲到 $(window).load
  • 壓縮js
  • 全面掌握jquery庫

1. 總是從ID選擇器(qì)開(kāi)始繼承

在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");

2. 在class前使用tag

第二快的選擇器(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");

3.将jquery對象緩存起來(lái)

要養成将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");
}

4. 掌握強大(dà)的鏈式操作(zuò)

上(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更輕量.

5.使用子查詢

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ù)

6.對直接的DOM操作(zuò)進行(xíng)限制(zhì)

這裏的基本思想是在內(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 選擇到
  • 元素 for (var i=0, l=top_100_list.length; i" + top_100_list[i] + "
  • "); }

    我們應該将整套元素字符串在插入進dom中之前全部創建好:

    var top_100_list = [...], 
    $mylist = $("#mylist"); 
    top_100_li = ""; // 這個(gè)變量将用來(lái)存儲我們的列表元素
    
    for (var i=0, l=top_100_list.length; i" + top_100_list[i] + "");
    }
    $mylist.html(top_100_li);

    我們在插入之前将多(duō)個(gè)元素包裹進一個(gè)單獨的父級節點會(huì)更快:

    var top_100_list = [...],
    $mylist = $("#mylist"),
    top_100_ul = "
    
      "; for (var i=0, l=top_100_list.length; i"; } top_100_ul += "
    "; //關閉無序列表 $mylist.replaceWith(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ò).

    7. 冒泡

    除非在特殊情況下, 否則每一個(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ò)錯了.

    8.消除無效查詢

    盡管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ù)緊跟在模塊之後.

    • Red
    • Yellow
    • Green

    你(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ù).
    }
    }
    }

    9. 推遲到 $(window).load

    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)合.

    10. 壓縮js

    推薦一個(gè)js在線壓縮地址: http://dean.edwards.name/packer/

    11. 全面掌握jquery庫

    知己知彼, 百戰百勝.  隻有(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/