.live().delegate()都是藉重DOM事件會由子元素一路向父元素Bubble Up的特性,在document或特定元素統一掛上事件函數,事件被觸發時再透過選擇器比對事件目標元素是否吻合,決定要不要執行事件邏輯,藉此提升效率,同時還能將"未來才會建立的元素"也納入事件的涵蓋範圍。(細節可參考舊文)

不過,.live()與.delegate()做的事幾乎一模一樣,依江湖上的說法,1.4版推出的.delegate()又比1.3版誕生的.live()來得有效率,理由何在?

以對<table id="t">下所有<td>加掛click事件為例,多半會寫成:
$("#t td").live("click", fn); $("#t").delegate("td", "click", fn);

當執行$("#t td").live(),jQuery會監聽document的click事件,再依event.target是否吻合選擇器"#t td"決定live()所指定的click事件要不要被觸發;若使用$("#t").delegate(),jQuery監聽click事件的對象則會由document換成<table id="t">,但也一樣是比對event.target是否為td決定要不要觸發事件。二者相比,將監聽對象由document縮小到table對效能有利! 因為$("#t td").live()會過濾比對document上所有子元素產生的click事件,而$("#t").delegate("td"…)只有在table內子元素被click時才進行比對過濾,避免了非目標區元素被click時的多餘過濾流程。不過,這部分的效能損耗其實可以避免,只要改寫成$("td", document.getElementById("t")),則.live()的監聽對象就會被縮小到table而非document,此一差異性就消失了。但是,真要比效能,.live()還是難逃敗陣的命運! 為什麼?

對.live()或.delegate()來說,"td"是未來click事件觸發時比對event.target用的選擇器,理論上保留字串就夠了。當寫成$("td", document.getElementById("t")),jQuery會找尋當下所有符合的td元素,建出jQuery集合物件,但這個耗費資源建立的物件卻沒有發揮任何作用,而這個無謂的物件建立過程,在td的數量很多的情境下,就足以產生明顯效能差異。

我設計了一個實驗來驗證:

<!DOCTYPE html>
 
<html>
<head>
    <title>.delegate() test</title>
    <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.4.js">  
    </script>
    <script>
        $(function () {
            $("#b1").click(function () {
                //準備記錄執行時間
                var st = new Date();
                //用.live()為#t td加掛click事件
                //注意: 以下的寫法會比$("#t td")更有效率
                $("td", document.getElementById("t"))
                .live("click", function () {
                    $("#s1").text("live - " + $(this).text());
                });
                //顯示執行時間
                alert(".live() ticks - " +
                    (new Date().getTime() - st.getTime()));
            });
            $("#b2").click(function () {
                //準備記錄執行時間
                var st = new Date();
                //先取得#t的jQuery物件,用.delegate()為td加掛click事件
                $("#t").delegate("td", "click", function () {
                    $("#s2").text("delegate - " + $(this).text());
                });
                //顯示執行時間
                alert(".delegate() ticks - " +
                    (new Date().getTime() - st.getTime()));
            });
            $("#b3").click(function () {
                //建立一個包含5萬cell的table
                var sb = [];
                var idx = 0;
                for (var r = 0; r < 2000; r++) {
                    sb.push("<tr>");
                    for (var c = 0; c < 25; c++)
                        sb.push("<td>" + (idx++) + "</td>");
                    sb.push("</tr>");
                }
                $("#t").html(sb.join('\n'));
            });
        });
    </script>
    <style>
        #t td { border: 1px solid gray; text-align: center; cursor: pointer; }
        .display span  
        {
            border: 1px solid red; display: inline-block; margin: 5px; 
            width: 100px; text-align: center; background-color: #dddddd;
        }
    </style>
</head>
<body>
<input type="button" id="b1" value="Test .live()" />
<input type="button" id="b2" value="Test .delegate()" />
<input type="button" id="b3" value="Create Table" />
<span class="display">
<span id="s1">&#160;</span>
<span id="s2">&#160;</span>
</span>
<table id="t"></table>
</body>
</html>

如上圖,Test .live()及Test .delegate()可攔載所有<td>的click事件,分別將<td>的文字內容顯示在第一列右側的兩個<span>中,而按下Create Table則會建出5萬個<td>。

第一個測試我們可以先按Test .live(),再按Test .delegate(),應該都是0 ticks完成,之後按Create Table建立<td>,點選<td>就可以驗證.live()、delegate()均成功攔截到click事件。

第二個測試,則是先按Create Table建立出5萬個<td>,再按Test .live()及Test .delegate(),在我的電腦上,按Test .delegate()仍是瞬間完成,按Test .live()卻要耗上35+ ticks,推測應就是前述建立5萬個<td>元素jQuery集合耗費的時間。

最後再補充一點,如果程式思維是針對某個元素進行一連串動作: 先針對其下的子元素掛上事件,然後再進行其他操作,.delegate()允許我們寫成$("#t").delegate("..", "click", fn).css("..", "..").attr("..", "..")的串接形式,符合jQuery的直覺寫法;而.live()由於需將子元素視為主體,就無法像.delegate()般一氣喝成,也算是.delegate()寫法的另一項優點。

參考資料:


Comments

# by pico.chang

第一行的"藉重"應該改成"借重"吧...

# by Jeffrey

to pico.chang, 依教育部重編辭典修訂本(http://dict.revised.moe.edu.tw/)的解釋: 借重 - 借用他人的力量,多用作請人幫忙的敬詞。儒林外史˙第二十二回:「如今要借重大爺,明日早晨把客座裡收拾乾淨了。」紅樓夢˙第六回:「若可以領我見一見更好;若不能,便借重嫂子轉致意罷了。」或作「藉重」。 我比較愛寫成"藉重"(感覺比較"雅",XD),不過"借重"是比較通俗的寫法,謝謝你的提醒。

# by walter

黑大 不好意思,問個其他問題 $("td", document.getElementById("t")) 這個種selector我在官網都找不到 不知道要去哪裡找這方法勒 謝謝

# by Jeffrey

to walter, 可參考http://api.jquery.com/jQuery/ jQuery( selector [, context] ) *selector = A string containing a selector expression *context = A DOM Element, Document, or jQuery to use as context 在本例中,document.getElementById("t")是一個DOM element,即context參數

# by Rz

1.7之後 通通改成 on/off了 Over time, jQuery has evolved three ways to attach events to elements: .bind() , .live(), and .delegate(). Underneath it all, though, the three event APIs call the browser’s event system; Our current event APIs aren’t going away soon, but to address the inconsistencies we’ve introduced a new and simple pair of event methods that can do the work of all three: $(elems).on(events, selector, data, fn); $(elems).off(events, selector, fn); 以上內容節錄至 1.7 beta1 說明 寫法不變,讚

# by Sourav Basal

Thanks for sharing this article that distinguishes jQuery .bind() vs .live() vs .delegate() vs .on(). And it clears in depth view before applying to bind event to the elements. Version comparison also supports when one method migrate to another one. Here is another links for differentiate between .bind() vs .live() vs .delegate() vs .on(). http://www.namasteui.com/differences-between-jquery-bind-vs-live-vs-delegate-vs-on/ Hope this helps too. Thanks a lot. -- Regards, Sourav Basak [Blogger, Entrepreneur, Thinker] Namaste UI

Post a comment