清除 dom 节点子节点时自动删除事件处理程序

发布于 2024-09-30 07:46:44 字数 97 浏览 1 评论 0原文

有没有办法内省 dom 节点以查看是否附加了事件处理程序,以便您可以有效地编写一个安全函数来清除 dom 节点,而不必担心事件处理程序留下的内存泄漏?我希望以通用的方式做到这一点。

Is there a way to introspect a dom node to see if there are event handlers attached, so you can effectively write a safe function to clear out the dom nodes without worrying about memory leaks left by event handlers? I was hoping to do this in a generic fashion.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浪漫人生路 2024-10-07 07:46:44

据我所知,这可能是不可能的,这是来自 mozilla 网站的引用:

https ://developer.mozilla.org/en/DOM/element.addEventListener#Memory_issues

内存问题

document.addEventListener("加载",
函数(事件){ obj.func(事件); },
假);

调用 addEventListener 到
匿名函数创建一个新的
每次的听众。呼唤
匿名移除事件监听器
功能没有任何影响。一位匿名者
函数每个创建一个唯一的对象
时间被称为,它不是一个
但引用现有对象
它可能会调用一个。添加事件时
听众以这种方式确保它是
仅添加一次,它是永久的(可以
不被删除)直到该对象
被添加到被销毁。

如果听众不是匿名的,你可以这样做。这是来自 YUI 库事件的一段代码:

        /**
         * Returns all listeners attached to the given element via addListener.
         * Optionally, you can specify a specific type of event to return.
         * @method getListeners
         * @param el {HTMLElement|string} the element or element id to inspect 
         * @param sType {string} optional type of listener to return. If
         * left out, all listeners will be returned
         * @return {Object} the listener. Contains the following fields:
         *   type:   (string)   the type of event
         *   fn:     (function) the callback supplied to addListener
         *   obj:    (object)   the custom object supplied to addListener
         *   adjust: (boolean|object)  whether or not to adjust the default context
         *   scope: (boolean)  the derived context based on the adjust parameter
         *   index:  (int)      its position in the Event util listener cache
         * @static
         */           
        getListeners: function(el, sType) {
            var results=[], searchLists;
            if (!sType) {
                searchLists = [listeners, unloadListeners];
            } else if (sType === "unload") {
                searchLists = [unloadListeners];
            } else {
                sType = this._getType(sType);
                searchLists = [listeners];
            }

            var oEl = (YAHOO.lang.isString(el)) ? this.getEl(el) : el;

            for (var j=0;j<searchLists.length; j=j+1) {
                var searchList = searchLists[j];
                if (searchList) {
                    for (var i=0,len=searchList.length; i<len ; ++i) {
                        var l = searchList[i];
                        if ( l  && l[this.EL] === oEl && 
                                (!sType || sType === l[this.TYPE]) ) {
                            results.push({
                                type:   l[this.TYPE],
                                fn:     l[this.FN],
                                obj:    l[this.OBJ],
                                adjust: l[this.OVERRIDE],
                                scope:  l[this.ADJ_SCOPE],
                                index:  i
                            });
                        }
                    }
                }
            }

            return (results.length) ? results : null;
        },

您可以在此处阅读更多内容:
http://developer.yahoo.com/yui/event/

From what I see it might not be possible, here is a quote from mozilla site:

https://developer.mozilla.org/en/DOM/element.addEventListener#Memory_issues

Memory issues

document.addEventListener("load",
function(event) { obj.func(event); },
false);

Calling addEventListener to an
anonymous function creates a new
listener each time. Calling
removeEventListener to an anonymous
function has no effect. An anonymous
function creates a unique object each
time is is called, it is not a
reference to an existing object though
it may call one. When adding an event
listener in this manner be sure it is
added only once, it is permanent (can
not be removed) until the object it
was added to is destroyed.

if the listener is not anonymous you could do it. Here is a piece of code from YUI library Event:

        /**
         * Returns all listeners attached to the given element via addListener.
         * Optionally, you can specify a specific type of event to return.
         * @method getListeners
         * @param el {HTMLElement|string} the element or element id to inspect 
         * @param sType {string} optional type of listener to return. If
         * left out, all listeners will be returned
         * @return {Object} the listener. Contains the following fields:
         *   type:   (string)   the type of event
         *   fn:     (function) the callback supplied to addListener
         *   obj:    (object)   the custom object supplied to addListener
         *   adjust: (boolean|object)  whether or not to adjust the default context
         *   scope: (boolean)  the derived context based on the adjust parameter
         *   index:  (int)      its position in the Event util listener cache
         * @static
         */           
        getListeners: function(el, sType) {
            var results=[], searchLists;
            if (!sType) {
                searchLists = [listeners, unloadListeners];
            } else if (sType === "unload") {
                searchLists = [unloadListeners];
            } else {
                sType = this._getType(sType);
                searchLists = [listeners];
            }

            var oEl = (YAHOO.lang.isString(el)) ? this.getEl(el) : el;

            for (var j=0;j<searchLists.length; j=j+1) {
                var searchList = searchLists[j];
                if (searchList) {
                    for (var i=0,len=searchList.length; i<len ; ++i) {
                        var l = searchList[i];
                        if ( l  && l[this.EL] === oEl && 
                                (!sType || sType === l[this.TYPE]) ) {
                            results.push({
                                type:   l[this.TYPE],
                                fn:     l[this.FN],
                                obj:    l[this.OBJ],
                                adjust: l[this.OVERRIDE],
                                scope:  l[this.ADJ_SCOPE],
                                index:  i
                            });
                        }
                    }
                }
            }

            return (results.length) ? results : null;
        },

you can read more here:
http://developer.yahoo.com/yui/event/

沫尐诺 2024-10-07 07:46:44

这取决于。可以有效地删除由 el.onclick = ... 等属性分配的简单事件处理程序,但在 IE 中没有通过 attachEvent() 添加的处理程序列表。 内存泄漏在其他浏览器中并不是什么大问题。

/**
* The purge function takes a reference to a DOM element as an argument. 
* It loops through the element's attributes. If it finds any functions, 
* it nulls them out. This breaks the cycle, allowing memory to be reclaimed. 
* It will also look at all of the element's descendent elements, and clear 
* out all of their cycles as well.
*  - http://javascript.crockford.com/memory/leak.html
*/
function purge(d) {
    var a = d.attributes, i, l, n;
    if (a) {
        l = a.length;
        for (i = 0; i < l; i += 1) {
            n = a[i].name;
            if (typeof d[n] === 'function') {
                d[n] = null;
            }
        }
    }
    a = d.childNodes;
    if (a) {
        l = a.length;
        for (i = 0; i < l; i += 1) {
            purge(d.childNodes[i]);
        }
    }
}

如果您想处理这两种情况并管理页面中的所有事件处理程序,您可以在自己的函数中包装 addEvent 功能,并在要删除元素时删除它们。

It depends. Simple event handlers assigned by property like el.onclick = ... can be effectively removed, but there is no list of handlers added via attachEvent() in IE. Memory leaks are not much of a concern in other browsers.

/**
* The purge function takes a reference to a DOM element as an argument. 
* It loops through the element's attributes. If it finds any functions, 
* it nulls them out. This breaks the cycle, allowing memory to be reclaimed. 
* It will also look at all of the element's descendent elements, and clear 
* out all of their cycles as well.
*  - http://javascript.crockford.com/memory/leak.html
*/
function purge(d) {
    var a = d.attributes, i, l, n;
    if (a) {
        l = a.length;
        for (i = 0; i < l; i += 1) {
            n = a[i].name;
            if (typeof d[n] === 'function') {
                d[n] = null;
            }
        }
    }
    a = d.childNodes;
    if (a) {
        l = a.length;
        for (i = 0; i < l; i += 1) {
            purge(d.childNodes[i]);
        }
    }
}

If you want to handle both cases and you manage all event handlers in your page you can wrap addEvent functionality in your own function, and delete them when an element is to be removed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文