如何同步AJAX调用可能导致内存泄漏?

我明白这个一般建议是针对使用同步ajax调用给出的,因为同步调用会阻止UI呈现。

通常给出的另一个原因是与同步 AJAX的内存泄漏问题。

从MDN文档 -

注意:不应该使用同步XMLHttpRequests,因为由于网络固有的异步性质,在使用同步请求时存在内存和事件泄漏的各种方式。 唯一的例外是同步请求在Worker中很好地工作。

同步调用如何导致内存泄漏?

我正在寻找一个实际的例子。 任何关于这个主题的文献都会很棒。


如果XHR按照规范正确实施,那么它不会泄漏:

如果XMLHttpRequest对象的状态为OPENED且send()标志设置,状态为HEADERS_RECEIVED或状态为LOADING,则不得进行垃圾收集,并且以下情况之一为真:

它有一个或多个事件监听器,其类型是readystatechange,progress,abort,error,load,timeout或loadend。

上传完成标志未设置,关联的XMLHttpRequestUpload对象具有一个或多个注册的事件侦听器,其类型为progress,abort,error,load,timeout或loadend。

如果XMLHttpRequest对象在其连接仍处于打开状态时进行垃圾收集,则用户代理必须取消由此对象打开的任何获取算法实例,放弃为其排队的任何任务,并丢弃从网络接收到的任何进一步数据。

所以在你点击.send() ,XHR对象(以及它引用的任何东西)变得对GC .send() 。 但是,任何错误或成功都会使XHR进入完成状态,并且会再次受GC影响。 如果XHR对象是同步或异步,则根本无关紧要。 如果再次发生长同步请求,则无关紧要,因为您只会在发送语句中卡住,直到服务器响应。

但是,根据这张幻灯片,至少在2012年的Chrome / Chromium中没有正确实施。根据规范,不需要调用.abort()因为DONE状态意味着XHR对象应该已经是正常的GCd。

我找不到任何证据支持MDN声明,并且我通过twitter与作者联系。


我认为内存泄漏的发生主要是因为垃圾收集器无法完成其工作。 也就是说你有一些参考,而GC不能删除它。 我写了一个简单的例子:

var getDataSync = function(url) {
    console.log("getDataSync");
    var request = new XMLHttpRequest();
    request.open('GET', url, false);  // `false` makes the request synchronous
    try {
        request.send(null);
        if(request.status === 200) {
            return request.responseText;
        } else {
            return "";
        }
    } catch(e) {
        console.log("!ERROR");
    }
}

var getDataAsync = function(url, callback) {
    console.log("getDataAsync");
    var xhr = new XMLHttpRequest();
    xhr.open("GET", url, true);
    xhr.onload = function (e) {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
                callback(xhr.responseText);
            } else {
                callback("");
            }
        }
    };
    xhr.onerror = function (e) {
        callback("");
    };
    xhr.send(null);
}

var requestsMade = 0
var requests = 1;
var url = "http://missing-url";
for(var i=0; i<requests; i++, requestsMade++) {
    getDataSync(url);
    // getDataAsync(url);
}

除了同步功能阻塞了很多东西外,还有一个很大的区别。 错误处理。 如果您使用getDataSync并删除try-catch块并刷新页面,您将看到引发错误。 这是因为url不存在,但现在的问题是抛出错误时垃圾收集器如何工作。 它是否清除了与错误相关的所有对象,是否保留错误对象或类似的东西。 如果有人对此有更多了解并写在这里,我会很高兴。


如果同步调用在完成之前被中断(即通过重新使用XMLHttpRequest对象的用户事件),那么未完成的网络查询可能会被挂起,无法进行垃圾回收。

这是因为,如果请求返回时启动请求的对象不存在,则返回无法完成,但(如果浏览器不完美)仍保留在内存中。 您可以使用setTimeout轻松地导致此请求在请求完成之后但返回之前删除请求对象。

我记得在2009年左右,我在IE中遇到了一个很大的问题,但我希望现代浏览器不会受到这个问题的影响。 当然,现代图书馆(即JQuery)可以防止发生这种情况,从而可以在不需要考虑的情况下提出请求。

链接地址: http://www.djcxy.com/p/1623.html

上一篇: How synchronous AJAX call could cause memory leak?

下一篇: What are deferred objects?