彗星:XMLHttpRequest.responseText无限增长

4

大家好,

我正在开发一个Comet 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);
}
1个回答

2

设置字段不会有帮助

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

我说“某个地方”,因为套接字数据通过几个软件层传递。只要您的XHR仍在进行中,您的运行时(浏览器或js运行时)将继续接收。它必须对内容执行解码(例如(解)gzip),并可能解码传输编码(如果是长时间运行的连接,则可能是'chunked')。

无论您访问还是设置属性,都存在一个基础增长缓冲区,其中包含(增长的)有效载荷。

至少在Chrome上,XMLHttpRequest.prototype.responseText仅定义为getter属性。设置它(例如使用xhr.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进行内存高效的消息块处理

当然,这假定在流上接收到的数据将是相同的,或者存在某种方法来唯一标识进入的消息,以使两个流“对齐”。

multipart/x-mixed-replace

曾经有这样一种内容类型,您可以设置它,这将指示客户端在接收到特定字符串时重置其响应。

它最初是为流式传输网络摄像头图像而设计的,但后来被滥用于Comet,并且在某种程度上可以实现您想要的功能,但至少从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提供,因此这并不足以解决内存泄漏问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接