談JavaScript中的移除空事件處理程序
每當(dāng)將事件處理程序指定給元素時,運行中的瀏覽器代碼與支持頁面交互的JavaScript代碼之間就會建立一個連接。這種鏈接越多,頁面執(zhí)行起來就越慢。所前所述,可以采用事件委托技術(shù),限制建立的連接數(shù)量。另外,在不需要的時代移除事件處理程序,也是解決這個問題的一種方案。內(nèi)存中留有那些過時不用的“空事件處理程序”,也是造成Web應(yīng)用程序內(nèi)存與性能問題的主要原因。
在兩種情況下,可能會造成上述問題,第一種情況就是從文檔 中移除帶有事件處理程序的元素時,這可能是通過純粹的DOM操作,例如使用removeChild()和replaceChild()方法,但更多地是發(fā)生在使用innerHTML替換頁面中某一部分的時候。如果帶有事件處理程序的元素被innerHTML刪除了,那么原來添加到元素中的事件處理程序極有可能被當(dāng)作垃圾回收。來看下面的例子:
- <div id="myDiv">
- <input type="button" value="Click Me" id="myBtn">
- </div>
- <script type="text/javascript">
- var btn=document.getElementById("myBtn");
- btn.onclick=function(){
- document.getElementById("myDiv").innerHTML="Processing…";
- }
- </script>
這里,有一個按鈕被包含在<div>元素中,為避免雙擊,單擊這個按鈕時就將按鈕移除并替換成一條消息;這是網(wǎng)站設(shè)計中非常流行的一種做法。但問題在于,當(dāng)按鈕被從頁面中移除時,它還帶著一個事件處理程序呢,在<div>元素中設(shè)置innerHTML可以把按鈕移走,但事件處理各種仍然與按鈕保持著引用聯(lián)系。有的瀏覽器(尤其是IE)在這種情況下不會作出恰當(dāng)?shù)奶幚?,它們很有可能會將對元素和事件處理程序的引用都保存在?nèi)存中。如果你想知道某個元即將被移除,那么最好手工移除事件處理程序。如下面的例子所示:
- <div id="myDiv">
- <input type="button" value="Click Me" id="myBtn">
- </div>
- <script type="text/javascript">
- var btn=document.getElementById("myBtn");
- btn.onclick=function(){
- btn.onclick=null;
- document.getElementById("myDiv").innerHTML="Processing…";
- }
- </script>
在此,我們設(shè)置<div>的innerHTML屬性之前,先移除了按鈕的事件處理程序。這樣就確保了內(nèi)存可以被再次利用,而從DOM中移除按鈕也做到了干凈利索。
注:采用事件委托也有解決這個問題。如果事先知道將來有可能使用innerHTML替換掉頁面中的某一部分,那么就可以不直接把事件處理程序添加到該部分的元素中,而通過把事件處理程序指定給最好層次的元素,同樣能夠處理該區(qū)域中的事件。
導(dǎo)致“空事件處理程序”的另一情況,就是卸載頁面中的時候。毫不奇怪,IE在這種情況下依然是問題最多的瀏覽器,盡管其他瀏覽器或多或少也有類似的問題。如果在頁面被卸載之前沒有清理干凈事件處理程序。那它們就會滯留在內(nèi)存中。每次加載完頁面再卸載頁面時(可能是在兩個頁面間來加切換,也可以是單擊了“刷新”按鈕),內(nèi)存中滯留的對象數(shù)目就會增加,因為事件處理程序占用的內(nèi)存并沒有被釋放。
一般來說,最好的做法是在頁面卸載之前 ,先通過onunload事件處理程序移除所有事件處理程序。在此,事件委托技術(shù)再次表現(xiàn)出它的優(yōu)勢——需要跟蹤的事件程序越少,移除它們就越容易,對這種類似的操作,我們可把它想象成:只要是通過onload事件處理程序添加的東西,最后都要通過onunload事件處理程序?qū)⑺鼈円瞥?/p>
注:不要忘了,使用onunload事件處理程序意味著頁面不會被緩存在bfcachek中,如果你在意這個問題,那么就只能在IE中通過onunload來移除事件處理程序了。
本文地址: http://www.yiiyaa.net/1361
【編輯推薦】