jQuery泄漏解决了,但为什么? [英] jQuery leaks solved, but why?

查看:104
本文介绍了jQuery泄漏解决了,但为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用大量JavaScript的大型企业应用程序。我完全不能修改所有在过去5年的发展中创造的小循环引用。在研究解决方案时,我遇到了这个小小的jQuery hack / patch:



http://kossovsky.net/index.php/2009/07/ie-memory-leak-jquery-garbage-collector/



,并决定尝试一下。令人惊讶的是,它的作品! sIEVE在我以前识别过的地方没有泄漏,而iexplore任务正在维护一个更易于管理的内存占用。



我的问题是,为什么这样做? jQuery.remove调用.removeChild,它应该摆脱元素,但显然不会。补丁会将目标元素附加到新的垃圾收集器div上,然后清除它。为什么删除补丁的方法完全释放内存,但jQuery的删除功能不会?我希望了解为什么这样工作,以便在检查更大的应用程序之前可能改进解决方案。

解决方案

这是当前jQuery版本(1.6.2)中的 .remove 方法。请注意,它调用 .cleanData

  // keepData是内部的只使用 - 不要文档
remove:function(selector,keepData){
for(var i = 0,elem;(elem = this [i])!= null; i ++){
if(!selector || jQuery.filter(selector,[elem]).length){
if(!keepData&& elem.nodeType === 1){
jQuery.cleanData (elem.getElementsByTagName(*));
jQuery.cleanData([elem]);
}

if(elem.parentNode){
elem.parentNode.removeChild(elem);
}
}
}

返回此;
},

而$ code> .cleanData 方法,它提到一个票号,据称防止这种可怕的泄漏(根据其中一条意见):

  cleanData:function(elems){
var data,id,cache = jQuery.cache,internalKey = jQuery.expando,special = jQuery.event.special,
deleteExpando = jQuery.support.deleteExpando;对于(var i = 0,elem;(elem = elems [i])!= null; i ++){
if(elem.nodeName&& jQuery.noData [elem .nodeName.toLowerCase()]){
continue;
}

id = elem [jQuery.expando];

if(id){
data = cache [id]&& cache [id] [internalKey];

if(data&& data.events){
for(var type in data.events){
if(special [type]){
jQuery.event.remove(elem,type);

//这是一个避免jQuery.event.remove的开销的快捷方式
} else {
jQuery.removeEvent(elem,type,data.handle);
}
}

//空的DOM引用以避免IE6 / 7/8泄漏(#7054)
if(data.handle){
data.handle.elem = null;
}
}

if(deleteExpando){
delete elem [jQuery.expando];

} else if(elem.removeAttribute){
elem.removeAttribute(jQuery.expando);
}

删除缓存[id];
}
}
}

这里是提到的门票在评论中。显然是八个月前固定的:



http://bugs.jquery.com/ticket/7054#comment:10



据Dave Methvin介绍,解决方案似乎是>确保cleanData删除事件处理程序中的DOM元素引用以避免IE6 / 7/8内存泄漏。



换句话说,设置引用事件处理程序中的DOM元素 null 否则一些令人敬畏的浏览器,没有提到任何名称咳嗽 IE咳嗽将泄漏记忆。



discardElement (从您的链接)将元素插入容器,然后清空容器,从而对该元素的任何引用



考虑到这一点,我建议升级jQuery。你指出的这个文章是从2009年开始的,两年大致相当于jQuery开发时间的四百九十亿工时。



最后,这里有一些有趣的阅读Internet Explorer中的泄漏模式:




I am working on a large enterprise application with a LOT of JavaScript. Enough that I can't possibly go through and fix all the small circular references that have been created over its past 5 years of development. While researching solutions I came across this small jQuery hack/patch:

http://kossovsky.net/index.php/2009/07/ie-memory-leak-jquery-garbage-collector/

and decided to try it. Amazingly, it works! sIEVE shows no leaks in the places I had previously identified them and the iexplore task is maintaining a more manageable memory footprint.

My question is, why does this work? jQuery.remove calls .removeChild, which should get rid of the element, but apparently does not. The patch instead appends the target element onto a new garbage collector div, which it then clears. Why does the patch method of removal completely free up the memory but jQuery's remove function does not? I'm hoping to understand why this works in order to possibly improve the solution before I check it in to the larger application.

解决方案

This is the .remove method in the current jQuery release (1.6.2). Notice that it calls .cleanData:

// keepData is for internal use only--do not document
    remove: function( selector, keepData ) {
        for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
            if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
                if ( !keepData && elem.nodeType === 1 ) {
                    jQuery.cleanData( elem.getElementsByTagName("*") );
                    jQuery.cleanData( [ elem ] );
                }

                if ( elem.parentNode ) {
                    elem.parentNode.removeChild( elem );
                }
            }
        }

        return this;
    },

And the .cleanData method which it calls, which mentions a ticket number and allegedly prevents that horrible leak (according to one of the comments):

cleanData: function( elems ) {
        var data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special,
            deleteExpando = jQuery.support.deleteExpando;

        for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
            if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
                continue;
            }

            id = elem[ jQuery.expando ];

            if ( id ) {
                data = cache[ id ] && cache[ id ][ internalKey ];

                if ( data && data.events ) {
                    for ( var type in data.events ) {
                        if ( special[ type ] ) {
                            jQuery.event.remove( elem, type );

                        // This is a shortcut to avoid jQuery.event.remove's overhead
                        } else {
                            jQuery.removeEvent( elem, type, data.handle );
                        }
                    }

                    // Null the DOM reference to avoid IE6/7/8 leak (#7054)
                    if ( data.handle ) {
                        data.handle.elem = null;
                    }
                }

                if ( deleteExpando ) {
                    delete elem[ jQuery.expando ];

                } else if ( elem.removeAttribute ) {
                    elem.removeAttribute( jQuery.expando );
                }

                delete cache[ id ];
            }
        }
    }

And here is the ticket mentioned in the comment. Apparently it was fixed eight months ago:

http://bugs.jquery.com/ticket/7054#comment:10

According to Dave Methvin the solution seems to be to Ensure that the DOM element ref in an event handler is removed by cleanData to avoid an IE6/7/8 memory leak.

In other words, set references to DOM elements within event handlers to null otherwise some awesome browsers, without mentioning any names cough IE cough will leak memory.

discardElement (from your link) inserts the element into a container, and then empties the container, thereby nullifying any references to that element.

With that in mind, I would suggest upgrading jQuery. The article you point to is from 2009, and two years is roughly equivalent to four-hundred-zillion man hours of jQuery development time.

Finally, here is some interesting (and ridiculously long) reading on leak patterns in Internet Explorer:

这篇关于jQuery泄漏解决了,但为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆