解决了
网络上有很多与此主题矛盾的信息。感谢@John,我设法弄清了闭包(如下所述)不是导致内存泄漏的原因,而且即使在IE8中,它们也不像人们所声称的那样普遍。实际上,我的代码中仅发生了1次泄漏,事实证明,修复起来并不难。
从现在开始,我对这个问题的回答将是:
IE8唯一一次泄漏的AFAIK是附加事件/在全局对象上设置处理程序的时间。 (window.onloadwindow.onbeforeunload,...)。为了解决这个问题,请参阅下面的答案。

巨大更新:
现在我完全迷路了……经过一段时间的研究,无论是新旧文章,我至少都面临着一个巨大的矛盾。而其中一位JavaScript大师(Douglas Crockford)说:

正如@freakish指出的那样,我的以下代码段类似于jQuery的内部工作原理,我对我的解决方案不会造成内存泄漏的感觉非常安全。同时,我找到了this MSDN page,其中Circular References with Closures部分是我特别感兴趣的部分。下图几乎是我的代码工作原理的示意图,不是吗:

唯一的区别是,我的常识是不将事件侦听器附加到元素本身。所有相同的Douggie都非常明确:闭包不是IE中内存泄漏的源头。这种矛盾使我对谁是正确的一无所知。
我还发现IE9也无法完全解决泄漏问题(找不到链接ATM)。
最后一件事:我还了解到IE是在JScript引擎之外管理DOM的,这使我在基于ajax请求更改<select>元素的子代时感到烦恼:

function changeSeason(e)
{
    var xhr,sendVal,targetID;
    e = e || window.event;//(IE...
    targetID = this.id.replace(/commonSourceFragment/,'commonTargetFragment');//fooHomeSelect -> barHomeSelect
    sendVal = this.options[this.selectedIndex].innerHTML.trim().substring(0,1);
    xhr = prepareAjax(false,(function(t)
    {
        return function()
        {
            reusableCallback.apply(this,[t]);
        }
    })(document.getElementById(targetID)),'/index/ajax');
    xhr({data:{newSelect:sendVal}});
}

function reusableCallback(elem)
{
    if (this.readyState === 4 && this.status === 200)
    {
        var data = JSON.parse(this.responseText);
        elem.innerHTML = '<option>' + data.theArray.join('</option><option>') + '</option>';
    }
}
如果IE确实确实像不存在JScript引擎一样管理DOM,那么使用此代码未释放选项元素的可能性是多少?我特意添加了此代码段作为示例,因为在这种情况下,我将作为闭包范围一部分的变量作为全局函数的参数传递。我找不到有关此做法的任何文档,但是基于Miscrosoft提供的文档,它应该中断可能发生的所有循环引用,不是吗?

警告:冗长的问题...(对不起)
我已经编写了一些相当大的JavaScript来在Web应用程序中进行Ajax调用。为了避免大量的回调和事件,我充分利用了事件委托(delegate)和关闭的优势。现在,我编写了一个让我想知道可能的内存泄漏的函数。尽管我知道IE> 8处理闭包的能力要比其前辈好得多,但公司的政策是始终支持IE 8。
在下面的示例中,我提供了关于here的示例,您可以找到一个类似的示例,尽管它不使用ajax,而是使用setTimeout,结果几乎相同。 (您当然可以跳过下面的代码,直接转到问题本身)
我想到的代码是这样的:
function prepareAjax(callback,method,url)
{
    method = method || 'POST';
    callback = callback || success;//a default CB, just logs/alerts the response
    url = url || getUrl();//makes default url /currentController/ajax
    var xhr = createXHRObject();//try{}catch etc...
    xhr.open(method,url,true);
    xhr.setRequestMethod('X-Requested-with','XMLHttpRequest');
    xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded');
    xhr.setRequestHeader('Accept','*/*');
    xhr.onreadystatechange = function()
    {
        callback.apply(xhr);
    }
    return function(data)
    {
        //do some checks on data before sending: data.hasOwnProperty('user') etc...
        xhr.send(data);
    }
}
除了onreadystatechange回调,所有其他内容都很简单明了。直接绑定(bind)处理程序时,我注意到IE的一些问题:xhr.onreadystatechange = callback;,因此是匿名函数。不知道为什么,但是我发现这是使其工作最简单的方法。
就像我说的那样,我使用了很多事件委托(delegate),因此可以想象,访问触发ajax调用的实际元素/事件可能会很有用。因此,我有一些如下所示的事件处理程序:
function handleClick(e)
{
    var target,parent,data,i;
    e = e || window.event;
    target = e.target || e.srcElement;
    if (target.tagName.toLowerCase() !== 'input' && target.className !== 'delegateMe')
    {
        return true;
    }
    parent = target;
    while(parent.tagName.toLowerCase() !== 'tr')
    {
        parent = parent.parentNode;
    }
    data = {};
    for(i=0;i<parent.cells;i++)
    {
        data[parent.cells[i].className] = parent.cells[i].innerHTML;
    }
    //data looks something like {name:'Bar',firstName:'Foo',title:'Mr.'}
    i = prepareAjax((function(t)
    {
        return function()
        {
            if (this.readyState === 4 && this.status === 200)
            {
                //check responseText and, if ok:
                t.setAttribute('disabled','disabled');
            }
        }
    })(target));
    i(data);
}
如您所见,onreadystatechange回调是函数的返回值,该函数在调用回调时提供对target元素的引用。多亏了事件委托(delegate),当我决定将其从DOM中删除时(我有时这样做),我不再需要担心可能绑定(bind)到该元素的事件。
但是在我看来,对于IE的JScript引擎及其垃圾回收器,回调函数的调用对象可能证明太多了:

我已经用FF和chrome测试了这个“构造”。它在那里工作得很好,但是这种关闭时的关闭调用栈会在关闭时(每次传递对DOM元素的引用)在IE(尤其是IE9之前的版本)中成为问题吗?

不,我不会使用jQuery或其他库。我喜欢纯JS,并且想尽可能多地了解这种被严重低估的语言。这些代码片段不是实际的复制粘贴示例,而是为IMO提供了一个很好的表示形式,说明了我在整个脚本中如何使用委派,闭包和回调。因此,如果某些语法不太正确,请随时进行更正,但是,这当然不是问题所在。

最佳答案

我曾经在非浏览器EcmaScript(err .. JScr ... JavaScript)项目上与Microsoft的JavaScript的前程序管理器一起工作。我们对闭包进行了长时间的讨论。最后,关键是它们难于使用GC,并非没有可能。我必须阅读DC关于MS如何“错误”地指出闭包会导致内存泄漏的讨论-因为在IE的较早实现中,闭包无疑是有问题的,因为它们很难用MS实现来垃圾回收。我感到奇怪的是,雅虎的一个人试图告诉MS架构师,他们代码的一个已知问题在其他地方。我很欣赏他的工作,但我看不出他在那里有什么基础。

请记住,您上面引用的文章是针对IE6的,因为IE7在撰写本文时仍处于开发阶段。

顺便说一句-感谢上帝,IE6已经死了(不要让我去挖掘葬礼图片)。虽然,不要忘记它的遗产...我还没有看到任何人提出可靠的论据,认为它在发布的第一天并不是世界上最好的浏览器-问题是他们赢得了浏览器大战。因此,这相当于他们历史上最大的失误之一-他们随后解雇了该团队,并且停滞了将近5年。 IE团队从事漏洞修复的人员只有4到5个,这造成了巨大的人才流失,并大大落后于曲线。当他们重新雇用团队并意识到他们在哪里时,他们已经落后了几年,因为处理单调的代码库的工作量越来越小,没人真正了解了。这是我作为公司内部人员的观点,但与该团队没有直接关系。

还要记住,IE从来没有针对闭包进行优化,因为没有ProtoypeJS(哎呀,没有Rails),而jQuery在Resig的脑海中几乎是一线曙光。

在撰写本文时,他们还针对具有256兆RAM的RAM的计算机,这些RAM也尚未报废。

在让我阅读了整本问题书之后,我认为将这一历史课交给您是很公平的。

最后,我的意思是,您引用的是过时的 Material 。是的,请避免在IE6中关闭,因为它们会导致内存泄漏-但是IE6中没有关闭?

最后,MS已经解决并继续解决这个问题。即使在那时,您也要进行某种程度的关闭。

我知道他们在IE8方面在这方面做了大量工作(因为我毫不犹豫的项目使用了非实时标准JavaScript引擎),并且这项工作一直持续到IE9/10中。 StatCounter(http://gs.statcounter.com/)认为IE7的市场份额已从一年前的6%下降到1.5%,并且在开发"new"网站时,IE7的相关性越来越低。您还可以为NetScape 2.0进行开发,该版本引入了JavaScript支持,但是这样做只会稍微减少一点。

真的...不要为了引擎不存在而过度优化。

07-28 00:48
查看更多