Ajax應用事件處理及瀏覽器內存泄漏實踐打賞

事件處理是 Ajax 應用中的重要組成部分,也是應用動態變化的源動力。本文詳細介紹了瀏覽器中的事件處理相關的內容,包括注冊事件監聽器、事件發生之后的傳播機制、編寫事件監聽器等,還介紹了 Dojo 對事件處理提供的支持。最后介紹了與瀏覽器內存泄露和性能相關的最佳實踐。

瀏覽器中的事件是 Ajax 應用動態變化的源動力。用戶通過輸入設備(主要是鍵盤和鼠標)與應用進行互動。對于用戶不同的動作,如點擊鼠標左鍵、右鍵、或是按下鍵盤上的回車鍵,瀏覽器會產生與之對應的事件。這些事件按照一定的規則在當前文檔樹中傳播。應用可以根據自己的需要,對特定的事件進行處理,以響應用戶的動作。這種事件驅動的方式,不僅在 Web 應用中被使用,在桌面應用中也廣泛流行。本文詳細介紹了瀏覽器中事件處理的各個方面,包括事件監聽器的注冊、事件的傳播、事件處理和其它高級話題。本文還介紹了如何使用 Dojo 提供的 dojo.connect()。本文中使用的 Dojo 版本是 1.4。下面首先介紹如何注冊事件監聽器。

注冊事件監聽器

注冊事件監聽器的目的是在事件發生的時候添加相應的處理邏輯。瀏覽器中的事件處理采用經典的觀察者(Observer)設計模式。對于可能產生的各種事件,Ajax 應用通過腳本在節點上關注自己感興趣的事件,并添加相應的處理邏輯。當相應的事件發生并傳播到監聽器注冊的節點時,處理邏輯會被調用。

由于歷史原因、瀏覽器之間的兼容性問題以及 W3C 的標準化工作,目前注冊事件監聽器的方式主要有三種,分別是 DOM 級別 0 定義的方式、W3C 規范定義的事件模型和 IE 獨有的事件模型。下面分別對這三種方式進行詳細的介紹。

DOM 級別 0 定義的方式

這種事件監聽器注冊方式是把事件處理方法作為 DOM 節點對象的屬性來設置。設置屬性就相當于為對應的事件注冊了監聽器。DOM 節點對象有不同的屬性與不同的事件類型相對應,如 onclick對應于鼠標的點擊、onsubmit對應于表單的提交、onkeydown對應于鍵盤上的鍵被按下等。

這種事件監聽器注冊方式由于出現得最早,有著很好的瀏覽器兼容性,使用起來也比較簡單。它的問題是由于事件處理方法被設置為 DOM 節點對象的屬性,因此對一個 DOM 節點的每種事件,最多只能有一個事件處理方法。之后設置的方法會覆蓋掉之前的方法。對于一個多人開發的比較復雜的 Ajax 應用來說,這會是一個不小的問題。很可能某個開發人員添加的事件處理方法被另外的開發人員無意中覆蓋,造成難以調試的問題。另外這種方式只支持事件的冒泡階段,不支持捕獲階段。

W3C 規范定義的事件模型

在 W3C 的 DOM 級別 2 規范中引入了與瀏覽器事件相關的內容。這其中一個重要的接口就是 EventTarget,用來表示一個事件的目標。對于一個事件目標,可以在其上注冊多個事件監聽器。DOM 中的節點(Node)實現了此接口。因此,文檔樹中的任何節點都可以作為事件目標,從而在其上注冊事件監聽器。注冊事件監聽器是通過 EventTarget接口的 addEventListener(type, listener, useCapture)方法來完成的。該方法的參數 type表示的是事件的類型,如 click、submit和 keypress等;參數 listener表示的是事件的處理方法;參數 useCapture表示是否啟用事件捕獲。這三個參數都是必須的。關于事件捕獲和冒泡的細節,下面章節會介紹。與 addEventListener()對應的是 removeEventListener(),用來從事件目標中刪除監聽器,其參數與 addEventListener()相同。

使用 W3C 規范定義的事件模型的最大好處是可以為每個節點的每個事件注冊多個監聽器。這些監聽器不會互相影響。當事件發生的時候,這些監聽器都會被觸發,但是具體的順序是不確定的。另外這也是符合標準的做法,并且同時支持事件的捕獲和冒泡。不過最大的問題是 IE 并不支持此事件模型。

IE 獨有的事件模型

IE 采用了與 W3C 規范不同的事件模型。該模型與 W3C 規范定義的事件模型有點類似。它使用 attachEvent(type, listener)和 detachEvent(type, listener)兩個方法來完成事件監聽器的注冊和刪除。與 W3C 規范中的 addEventListener()和 removeEventListener()方法相比,這兩個方法都少了一個參數。這是由于 IE 并不支持事件的捕獲。另外事件的類型也必須以“on”開頭,如 onclick、onsubmit和 onkeypress等。

IE 獨有的事件模型也支持為每個元素的每個事件注冊多個監聽器。不過該模型只在 IE 中有效,在其它瀏覽器中,需要使用 W3C 規范定義的事件模型。

代碼清單 1 中給出了如何分別使用這三種方式為一個元素注冊鼠標點擊事件的監聽器。
清單 1. 三種事件監聽器注冊方式示例

var node = document.getElementById("myDiv");
 node.onclick = function() {
    alert("DOM 級別 0 事件注冊");
 };
 if (node.addEventListener) {
    node.addEventListener("click", function() {
        alert("W3C 事件模型");
    }, false);
 }
 if (node.attachEvent) {
    node.attachEvent("onclick", function() {
        alert("IE 事件模型");
    });
 }

在介紹了如何注冊事件監聽器之后,下面介紹事件發生之后在當前文檔樹中的傳播方式。

事件傳播

用戶通過輸入設備產生的動作會被瀏覽器捕獲,瀏覽器產生與之對應的事件。當事件產生之后,會在當前文檔樹中按照一定的規則進行傳播。每個事件都一個對應的目標,在文檔樹中有一個節點與此目標對應,稱為目標節點。比如點擊一個按鈕,那么產生的鼠標點擊事件的目標節點就是此按鈕。事件的傳播分成三個階段進行:捕獲階段、目標階段和冒泡階段。下面分別進行說明。

捕獲階段:事件首先從文檔的根節點開始,傳播給目標節點的祖先節點,直到目標節點的直接父節點。

目標階段:事件傳播到目標節點。

冒泡階段:事件從目標節點的直接父節點開始,傳播到目標節點的祖先節點,直到文檔的根節點。

圖 1 中給出了事件傳播過程的示意圖。圖中的箭頭表示了事件的傳播方向。
圖 1. 事件傳播過程示意圖
domevent
從上面的過程可以看出,事件的傳播與目標節點及其祖先節點密切相關。目標節點及其祖先節點在事件發生的 時候就確定了,并且在整個傳播過程中不會改變。即便是有祖先節點被刪除,傳播也是根據之前確定的節點來進行。不是所有的事件傳播都需要經歷上面的三個階段,可以通過腳本來取消某個階段的傳播。具體的做法在下面會提到。不同瀏覽器對事件傳播階段的支持也不相同。如 IE 只支持事件的冒泡階段,而不支持捕獲階段。

在注冊事件監聽器的時候,可以選擇在事件傳播的捕獲階段還是冒泡階段進行觸發。下面分別介紹這兩種情況。

注冊事件監聽器到捕獲階段

只有 W3C 規范定義的事件模型支持把事件監聽器注冊到捕獲階段。在使用 addEventListener()注冊事件監聽器的時候,通過把第三個參數的值設為 true,就把此監聽器聲明為在捕獲階段觸發。該監聽器可以攔截其目標節點的后代節點上的相同類型的事件,也就是說該監聽器的觸發是先于其后代節點上的監聽器的。這樣的話,該監聽器就有可能改變事件的傳播。代碼清單 2 中給出了注冊事件監聽器到捕獲階段的示例。

清單 2. 注冊事件監聽器到捕獲階段的示例
HTML 代碼片段

<div id="parentDiv">
<div id="myDiv1"> 點擊我 1</div>
<div id="myDiv2"> 點擊我 2</div>
</div>

JavaScript 代碼

var parentNode = document.getElementById("parentDiv");
node = document.getElementById("myDiv1");
if (parentNode.addEventListener) {
        parentNode.addEventListener("click", function() {
        alert("點擊父節點");
}, true);
        node.addEventListener("click", function() {
       alert("點擊子節點 1");
}, false);
}

如 代碼清單 2 所示,在父節點 parentNode上注冊了鼠標點擊事件在捕獲階段的監聽器,因此點擊子節點的時候,父節點上的監聽器方法也會被調用,而且是先于子節點上事件監聽器的。因此點擊 ID 為 myDiv1的子節點的時候,會依次彈出對話框“點擊父節點”和“點擊子節點 1”。

注冊事件監聽器到冒泡階段

有三種方式可以把監聽器注冊到事件傳播的冒泡階段:一種是 DOM 級別 0 的方式,另外一種是 W3C 事件模型中的 addEventListener()的第三個參數的值為 false,最后一種是 IE 事件模型中的 attachEvent()。當事件傳播到目標節點之后,會繼續傳播給其祖先節點。在這個過程中,祖先節點上注冊的冒泡階段監聽器會被觸發。代碼清單 3 給出了注冊事件監聽器到冒泡階段的示例。

清單 3. 注冊事件監聽器到冒泡階段的示例

var parentNode = document.getElementById("parentDiv"),
    node = document.getElementById("myDiv1");
 if (parentNode.addEventListener) {
    parentNode.addEventListener("click", function() {
        alert("點擊父節點(捕獲階段)");
    }, true);
    parentNode.addEventListener("click", function() {
        alert("點擊父節點(冒泡階段)");
    }, false);
    node.addEventListener("click", function() {
        alert("點擊子節點 1");
    }, false);
 }

代碼清單 3 中給出了示例的 JavaScript 代碼,HTML 代碼片段與 代碼清單 2 中的是相同的。當點擊 ID 為 myDiv1的節點時,首先父節點上的捕獲階段的監聽器被調用,接著是目標節點上的監聽器,最后是父節點上冒泡階段的監聽器。因此會依次彈出對話框“點擊父節點(捕獲階段)”、“點擊子節點 1”和“點擊父節點(冒泡階段)”。

當事件在各個節點上按照上述過程傳播的時候,可能觸發節點上注冊的事件監聽器。事件監聽器被觸發需要滿足三個條件:

事件的類型與注冊時指定的類型相同。

事件當前的傳播階段與注冊時指定的階段相同。在冒泡階段的事件并不會觸發注冊到捕獲階段的監聽器。

DOM 級別 3 規范引入了事件監聽器分組的概念。一個事件監聽器可能阻止同組的事件監聽器被觸發,而其它組的事件監聽器不受影響。一般可以忽略這個條件。

在介紹了事件的傳播過程之后,下面介紹在事件監聽器中處理發生的事件。

事件處理

注冊事件監聽器的目的是在感興趣的事件發生的時候,執行所需的應用邏輯。事件監聽器是一個 JavaScript 方法。事件監聽器被觸發即此 JavaScript 方法被調用。在處理事件的時候,需要獲取與此事件相關的上下文信息。這些信息是保持在一個事件對象中的。

事件對象

事件對象中包含了與事件相關的上下文信息,如事件類型和目標節點等。不同類型的事件所包含的信息也不相同,如鼠標點擊事件包含鼠標點擊的位置,而鍵盤事件包含按鍵的編碼以及是否同時按下了 Shift、Alt 和 Ctrl 等鍵。

獲取此事件對象的方式在 IE 和其它瀏覽器上是不同的。IE 把此對象存放在全局的 window.event變量中,而其它瀏覽器則把此對象作為事件監聽器 JavaScript 方法調用時的第一個參數。不同的瀏覽器中事件對象包含的屬性也是不同的。同樣含義的屬性其名稱也可能不同。如 W3C 規范中表示事件目標節點的屬性是 target,而 IE 使用的是 srcElement。在下面介紹具體的瀏覽器事件時,會介紹其事件對象所包含的詳細內容。

this 所引用的對象

在編寫事件監聽器的 JavaScript 方法的時候,很可能需要用到 JavaScript 中的 this關鍵詞。如果不顯式指定的話,this所引用的對象會根據事件監聽器注冊的方式而有所不同。

DOM 級別 0 定義的方式:this指向的是當前節點。

W3C 規范定義的事件模型:this指向的是當前節點。

IE 獨有的事件模型:this指向的是全局對象,即 window對象。

從上面可以看到,IE 采用了與眾不同的做法,而這種做法并不符合開發人員一般的理解。為了避免這種不一致可能帶來的問題,一種做法是顯式指定 this所引用的對象,可以通過 dojo.hitch()來實現;另外一種做法是對 IE 做特殊處理,使其符合 W3C 規范的標準做法。很多 JavaScript 框架都做了這種處理。

阻止事件傳播

前面介紹了事件傳播過程的三個階段,事件監聽器的處理方法中可以通過腳本來阻止事件的傳播過程。這樣的話可以阻止其它事件監聽器被觸發。W3C 規范定義的事件模型中,事件對象的方法 stopPropagation()可以用來阻止事件的繼續傳播。如果一個節點上注冊有多個事件監聽器,其中一個事件監聽器調用了 stopPropagation()來阻止事件傳播,該節點上的其它事件監聽器并不會受到影響,仍然會被觸發。受影響的是事件傳播路徑上的后續節點上的事件監聽器。W3C 規范定義的事件模型支持事件的捕獲和冒泡兩個階段,stopPropagation()對兩個階段都有影響。對 IE 獨有的事件模型來說,阻止事件傳播是通過設置事件對象的 cancelBubble屬性來完成的。代碼 window.event.cancelBubble = true;會阻止事件的冒泡階段。IE 也只支持冒泡階段。代碼清單 4 給出了阻止事件傳播的示例

清單 4. 阻止事件傳播的示例

var parentNode = document.getElementById("parentDiv"),
    node = document.getElementById("myDiv1");
 if (parentNode.addEventListener) {
    parentNode.addEventListener("click", function(e) {
        alert("點擊父節點(捕獲階段)");
        e.stopPropagation();
    }, true);
    node.addEventListener("click", function() {
        alert("點擊子節點 1");
    }, false);
 }
 if (parentNode.attachEvent) {
    node.attachEvent("onclick", function() {
        alert("點擊子節點 1");
        window.event.cancelBubble = true;
    });
    parentNode.attachEvent("onclick", function() {
        alert("點擊父節點(冒泡階段)");
    });
 }

如 代碼清單 4 所示,對 W3C 規范定義的事件模型和 IE 獨有的事件模型采用了不同的處理方法。父節點 parentNode上的捕獲階段的事件監聽器阻止了事件的傳播,因此點擊子節點之后,事件傳播到父節點上,其上的事件監聽器被觸發,但是子節點上事件監聽器并不會被觸發。IE 事件模型上的處理與此類似,不同的是發生在冒泡階段。在 IE 上只會彈出對話框“點擊子節點 1”,在其它瀏覽器上只會彈出對話框“點擊父節點(捕獲階段)”。

阻止瀏覽器默認行為

對于某些事件來說,瀏覽器會有對應的默認行為。比如點擊一個超鏈接的時候,瀏覽器會打開此鏈接。該點擊動作也會觸發此“a”元素上注冊的 click事件的監聽器。如果希望阻止瀏覽器默認行為的方式,W3C 規范定義的事件模型中可以調用事件對象的 preventDefault()方法來實現。IE 獨有的事件模型中可以通過設置事件對象的 returnValue屬性的值為 false來實現。

在介紹完事件處理相關的內容之后,下面介紹 Dojo 提供的 dojo.connect()方法。

dojo.connect

dojo.connect()是 Dojo 提供的通用的事件處理方法。使用它可以為任何 JavaScript 方法或 DOM 事件添加監聽器。當該 JavaScript 方法被調用或是 DOM 事件發生的時候,監聽器都會被觸發。對于 DOM 事件來說,dojo.connect()方法為開發人員解決了不同瀏覽器之間的兼容性問題。使用它編寫事件監聽器變得更加容易。dojo.connect()的方法聲明是 dojo.connect(obj, event, context, method, dontFix),其中參數 obj表示 JavaScript 方法所在的對象或是 DOM 節點;event表示 JavaScript 方法的名稱或是 DOM 事件的類型;context表示監聽器方法調用時 this所指向的對象;method表示監聽器方法;如果 obj是 DOM 節點的話,dontFix的值為 true表示不把此事件代理給瀏覽器處理。

用 dojo.connect()進行事件注冊的好處在于它很好的解決了不同瀏覽器之間的兼容性問題。首先是事件監聽器方法中 this所指向的對象,通過 dojo.connect()的參數 context就可以進行指定。另外一個是事件對象中所包含的信息。Dojo 對 IE 獨有的事件模型的事件對象做了處理,使其符合 W3C 規范定義的事件模型。事件對象總是作為事件監聽器方法的第一個參數出現。由于 IE 只支持事件傳播的冒泡階段,dojo.connect()是把事件監聽器添加到事件傳播的冒泡階段。如果想添加到捕獲階段,需要直接使用 addEventListener()。代碼清單 5 中給出了使用 dojo.connect()注冊事件監聽器的示例。

清單 5. 使用 dojo.connect()注冊事件監聽器的示例

dojo.connect(dojo.byId("parentDiv"), "click", function(e) {
    alert(e.target.tagName);
 });

如 代碼清單 5 所示,使用 dojo.connect()進行事件注冊的代碼非常簡單,并且對主流瀏覽器都適用。dojo.connect()返回的是當前事件綁定的標識符,可以通過 dojo.disconnect()來取消此綁定。Dojo 提供了 dojo.stopEvent()方法來阻止事件傳播和瀏覽器的默認行為,該方法惟一的參數是事件對象。

在介紹完 dojo.connect()方法之后,下面介紹瀏覽器中幾類重要的事件。

幾類重要的事件

下面重點介紹幾類瀏覽器中的常見事件,包括鼠標、鍵盤和頁面事件。

鼠標事件

與鼠標相關的事件主要有 click、mousedown、mouseup、mouseover、mousemove和 mouseout,分別表示鼠標點擊、鼠標鍵按下、鼠標鍵釋放、移動到元素上、在元素上移動和移動出元素。包含這些事件上下文信息的事件對象是在 DOM 級別 2 規范中標準化的,其中包含的信息如 表 1 所示。

表 1. 鼠標事件中的屬性

屬性 說明
screenX/screenY 分別表示事件發生時鼠標位置在屏幕坐標系統中的 X 軸和 Y 軸上的位置。
clientX/clientY 分別表示事件發生時鼠標位置在瀏覽器窗口坐標系統中 X 軸和 Y 軸上的位置。
pageX/pageY 分別表示事件發生時鼠標位置在當前頁面坐標系統中 X 軸和 Y 軸上的位置。這兩個屬性與 clientX/clientY的區別在于,頁面的大小可能超過瀏覽器窗口而出現滾動條。
layerX/layerY 分別表示事件發生時鼠標位置相對于事件目標在 X 軸和 Y 軸上的位置。
relatedTarget 表示與事件相關的另外一個事件目標節點。目前只使用在 mouseover和 mouseout事件中,分別表示鼠標離開的節點和鼠標進入的節點。

除了 表 1 中給出的屬性之外,鼠標事件對象還包含與鼠標按鍵相關的信息。Dojo 提供了一些幫助方法用來檢測鼠標按鍵:dojo.mouseButtons.isLeft(e)、dojo.mouseButtons.isMiddle(e)和 dojo.mouseButtons.isRight(e)分別用來檢測鼠標左鍵、中鍵和右鍵,其參數 e表示的是事件對象。

鍵盤事件

與鍵盤相關的事件有 keydown和 keyup,分別鍵盤上的鍵被按下和釋放。鍵盤事件是在 DOM 級別 3 規范中標準化的,其中包含的信息如 表 2 所示。
表 2. 鍵盤事件中的屬性

屬性 說明
keyCode 表示鍵盤上按鍵的編碼。
charCode 表示鍵盤上按鍵對應的字符編碼。
altKey/ctrlKey/shiftKey 分別表示鍵盤事件發生時,鍵 Alt/Ctrl/Shift 是否被同時按下。

在鍵盤事件的監聽器方法中,一般是通過 keyCode來判斷按下或是釋放的鍵。在不同的瀏覽器上,同樣的按鍵的編碼可能不同。Dojo 的 dojo.keys中提供了瀏覽器兼容的按鍵編碼。比如需要檢測是否按下了回車鍵,最好用 e.keyCode == dojo.keys.ENTER來實現。

頁面事件

與頁面相關的事件主要有 load、unload、resize和 scroll,分別表示頁面加載完成、用戶離開當前頁面、頁面大小發生改變和在頁面內發生滾動。由于前兩種事件比較常用,Dojo 提供了方法 dojo.addOnLoad()和 dojo.addOnUnload()來方便注冊這兩種事件的監聽器。

在介紹完幾類重要的事件之后,下面介紹一些高級話題。

高級話題

在介紹完瀏覽器中事件相關的基本內容之后,下面討論一些高級話題。首先從避免瀏覽器中的內存泄露開始。

避免內存泄露

DOM 的事件處理通常與瀏覽器中的內存泄露聯系在一起,尤其在 IE 中。在事件監聽器方法中很容易不正確的使用閉包,造成 DOM 節點對象和 JavaScript 對象之間的循環引用。IE 的垃圾回收機制不能正確處理這種循環引用,從而導致內存泄露。代碼清單 6 中給出了一種典型的內存泄露模式。

清單 6. 典型的瀏覽器內存泄露模式

function addEvent(element) {
    function handler() {
        alert("點擊!");
    }
    element.attachEvent("onclick", handler);
    }
    addEvent(document.getElementById("myDiv"));

在 代碼清單 6 中,通過 element.attachEvent()方法,DOM 節點對象引用了 JavaScript 方法 handler,而方法 handler由于在外部方法 addEvent之內,它有外部方法 addEvent的參數 element的引用。這樣就形成了循環引用,其結果是 DOM 節點對象 element和 JavaScript 方法 handler所占用的內存都不會被釋放。為了避免造成內存泄露,下面提供幾條比較好的實踐經驗。

使用 dojo.connect()注冊事件監聽器。這樣不僅兼容性更好,而且減少了無意中創建的閉包,不容易造成內存泄露。

事件監聽器方法應該盡可能的簡單。方法體的代碼應該盡可能的少,把業務邏輯代理給其它方法來完成。這樣做的好處是容易識別出其中的對象引用,便于檢查是否有內存泄露。

盡量不要在事件監聽器方法中為 DOM 節點對象添加額外的屬性。有時候為了維護狀態,可能會把一些屬性存放在 DOM 節點對象中,如 document.getElementById("myDiv").myVal = "A string.";。這樣做的缺點是如果該 DOM 節點對象無法被回收,這些額外的屬性也會無法被回收,造成更多的內存泄露。應該考慮使用其它的維護狀態的做法,比如狀態只保存在與 DOM 節點無關的普通 JavaScript 對象中,或是把狀態保存在 DOM 節點的屬性中。即便把額外的屬性添加到 DOM 節點對象中,也盡可能只添加基本數據類型的屬性,即字符串、布爾值和數字值等。如果添加 JavaScript 方法到 DOM 節點對象中,有很大可能會由于編程錯誤造成內存泄露。

顯式的刪除對象引用。在有些情況下,通過顯式地把對象引用設成 null,或是調用 delete來刪除。這樣的好處是可以顯式的解除循環引用。

性能

用戶在使用 Ajax 應用中,會產生相當多的事件。高效的處理這些事件,是提高用戶體驗的一個重要因素。雖然事件的處理時間在很大因素上取決于要完成的業務邏輯,但還是有一些比較好的實踐能夠提高事件處理的性能。

第一條實踐是減少事件監聽器的注冊,充分利用事件的傳播機制。由于 IE 只支持事件的冒泡階段,一般都是只針對事件的冒泡階段。根據事件的冒泡方式,子節點上發生的事件會傳播到其祖先節點上。如果需要為多個子節點添加邏輯相同的事件監聽器,更好的做法是把監聽器添加到其某個祖先節點上。這樣的話就會減少事件監聽器的數量。代碼清單 7 中給出了一個示例。

清單 7. 高效注冊事件監聽器的示例
HTML 代碼片段

<div id="parentDiv">
<div> 子節點 1</div>
<div> 子節點 2</div>
<div> 子節點 3</div>
</div>

JavaScript 代碼

dojo.connect(dojo.byId("parentDiv"), "click", function(e) {
var target = e.target;
if (dojo.hasClass(target, "item")) {
alert(target.innerHTML);
}
});

在 代碼清單 7 中,事件監聽器注冊在父節點 parentDiv上,當事件發生的時候,首先需要判斷事件目標節點是不是感興趣的子節點。如果是的話,就執行對應的業務邏輯。這樣的判斷是必須的,是為了保證處理的事件發生在正確的節點上。如果把事件監聽器注冊在子節點上的話,則需要三個監聽器,從而帶來更大的開銷。

第二條實踐是適時的阻止事件傳播。在開發某個組件的時候,在其 DOM 節點的事件監聽器完成處理之后,就可以調用 dojo.stopEvent(e)來阻止事件繼續傳播。這樣做的好處是避免事件繼續傳播,錯誤地觸發其它節點上的事件監聽器。當 Ajax 應用比較復雜,并且其中包含的組件比較多的時候,適時的阻止事件傳播可以減少組件間的互相影響。

文章收集整理自互聯網,版權歸原作者所有。

Ajax應用事件處理及瀏覽器內存泄漏實踐
文章《Ajax應用事件處理及瀏覽器內存泄漏實踐》二維碼
  • 微信打賞
  • 支付寶打賞

已有18條評論

  1. 無鉛焊臺

    看不懂

    2013-07-12 08:50 回復
  2. 蘇蘇網賺博客

    確實看不懂

    2013-04-03 21:20 回復
  3. 百樂坊

    頂頂頂上一貼。

    2013-03-18 11:41 回復
  4. 蘇昕

    你好,交換個友情鏈接不,我的網站:www.rumenla.com/ 你看一下吧,如果覺得可以,我們可以互換一下。如果不行,也沒關系,認識你也很不錯!

    2013-03-17 18:59 回復
  5. 合肥做網站公司

    事件從目標節點的直接父節點開始,傳播到目標節點的祖先節點,直到文檔的根節點。

    2013-03-15 15:55 回復
  6. hostgator

    文章分享的好有深度,來學習一下

    2013-03-15 13:26 回復
  7. 新世紀娛樂城

    果斷技術貼,小菜表示看不懂~

    2013-03-15 11:44 回復
  8. 大蔥

    好長~~~

    2013-03-13 16:56 回復
  9. 變壓器

    這個看的一知半解的,不太懂

    2013-03-13 10:29 回復
  10. 養生

    看起來不錯哦

    2013-03-07 12:11 回復
  11. 廣告機

    比較詳細的解答哦,不過還有很多問題需要詳細的解答。

    2013-03-05 19:14 回復
  12. 土撥鼠

    ajax 還需學習

    2013-03-04 15:47 回復
  13. 我的名字叫麒

    看不懂,友情頂帖!

    2013-03-04 14:17 回復
  14. airoschou

    最近一直在接觸ajax嘛,這方面不太通,要多學習了

    2013-03-04 10:01 回復
    • 樸人博客

      無奈,網上找資料中,做了個全ajax站,ie下內存泄露太嚴重了

      2013-03-04 19:23 回復
  15. 不亦樂乎

    Ajax一個非常酷斃的東東。

    2013-03-01 09:45 回復

(必填)

(必填)

(可選)

黑龙江22选5开奖