3

全部,

我正在实现一个彗星 JS 库。现在我正在跟踪响应文本的大小并在块到达时返回新部分。这为我的回调提供了新数据,但这是一个非常明显的内存泄漏。有没有办法强制关闭 XMLHttpRequest 对象或定期重置 responseText 的内容?

request.multi = function(type, handler, url, querystring){
    querystring  = (querystring == undefined) ? null: querystring;

    var response = "";
    var handle   = makeRequestHandle();

    handle.multipart = true;
    handle.open(type, url, true);
    handle.onreadystatechange = function(){
        var return_val;
        if(handle.readyState == 4){
            m_log.debug("Conection died");
        }else if(handle.readyState == 3){
            return_val = handle.responseText.substring(response.length);
            response   = handle.responseText;
            handler(return_val);
        }else{
            m_log.debug("readyState %s", handle.readyState);
        }
    };
    handle.send(querystring);
}
4

1 回答 1

1

设置字段无济于事

您是正确的,只要请求处于活动状态并且您的处理程序使用它,您就在内存中的某处累积数据。

我说“某处”,因为套接字数据会通过几个软件层。只要您的 XHR 正在进行,您的运行时(浏览器或 js 运行时)就会继续接收。它必须对内容执行解码(例如(un)gzip),并且可能对传输编码进行解码(如果是长时间运行的连接,可能会被“分块”)。

无论您是否访问或设置该属性,都有一个包含(增长的)有效负载的底层增长缓冲区。

至少在 Chrome 上,XMLHttpRequest.prototype.responseText仅定义为 getter 属性。设置它(例如 withxhr.responseText = ''对底层缓冲区没有影响。内存将不断增长

// you can verify
var xhr = new XMLHttpRequest();
Console.log(Object.getOwnPropertyDescriptor(x.__proto__, "response"))

// I get
{... get: function () {...}, set: undefined }

对于您在 xhr 有效负载上可能拥有的其他“视图” xhr.response(对于 blob)和xhr.responseXML.

用第二个 XHR 做探戈

让您的连接内存“重置”而不丢失消息的最可靠方法是在旧的 ajax 请求仍处于活动状态时启动新的 ajax 请求,并在旧的接收到完整的最后一条消息后切换到新的请求。虽然两者都处于活动状态,但必须忽略新流上的数据,直到它们处于“同步”状态。

使用 XMLHttpRequest 的内存高效消息块处理

这当然假设在流上接收到的数据是相同的,或者有某种方法可以唯一地识别传入的消息以使两个流“对齐”。

多部分/x-混合替换

曾经有一个你可以设置的内容类型,它会指示客户端在收到特定字符串时重置其响应。

它是为流式传输网络摄像头图像而设计的,在彗星上被滥用了一段时间,并且可以满足您的需求,但至少 Firefox 和 Chrome 放弃了对它的支持。众所周知,它从一开始就不受 IE 的支持,所以今天可能也是如此。

Content-type: multipart/x-mixed-replace;boundary=<randomstringhere>

哪些<randomstringhere>内容不太可能出现在您的应用程序消息中。在服务器发出的每条消息“推送”之间,您插入<randomstringhere>. responseText浏览器会自动在每个边界处重置。

该问题的一个问题是,您必须在浏览器收到下一条消息之前处理边界中的所有消息。所以这很有趣,至少对于 AJAX 来说是这样。

简化您的生活x.response

在问题中给出的示例中,responseText 用于获取完整的有效负载。在send()调用之前,可以设置 handle.responseType = "text",然后在进度回调中,handle.response将只携带自上次调用处理程序以来的新信息。

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/response

然而,有可能整个有效负载仍然可以通过 获得responseText,因此这不足以解决内存失控问题。

于 2017-03-04T06:28:08.057 回答