XMLHttpRequest和范围的影响

时间:2014-06-23 19:26:36

标签: javascript php ajax

Bounty注意:简单的问题是,如果是异步请求,为什么我不必担心在请求完成之前删除goGet

我有一个用PHP生成的表单,它生成许多HTML行,我将其称为“条目”。每个条目都有两个选项,“删除”和“编辑”,每个选项可能需要创建零个或多个XMLHttpRequest

为了尝试使处理请求易于管理,我创建了一个XmlHttpRequest类,如下所示:

function XmlHttpRequest(inElement) {
    this.request = new XMLHttpRequest();
    this.write = inElement;

    var self = this;
    this.request.onreadystatechange = function() {
        self.write.innerHTML = (self.request.readyState == 4) ? self.request.responseText : "Please wait…";
    }
}

XmlHttpRequest.prototype.post = function(inFile, inPost) {
    this.request.open("POST", inFile, true);
    this.request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    this.request.send(inPost);
}

当点击删除或编辑时,他们会调用函数,其中一个是:

function getForm(inEntryId, inTemplateId) {
    var key = "form"+inEntryId;
    if (!requested[key]) {
        var goGet = new XmlHttpRequest(document.getElementById("hideOptions"+inEntryId));
        goGet.post("getForm.php", "id="+inEntryId+"&template="+inTemplateId);
    }
    requested[key] = true;
}

这似乎工作得很好。但是,在写完这篇文章之后,我开始担心当getForm()中的执行结束时,goGet可能会在请求完成之前被移除,并且该过程无法在function XmlHttpRequest()内完成,{ {1}}。

这是我需要担心的事情(所以我必须与每个this.request.onreadystatechange = function()保持某种全局联系)?

编辑:我觉得在使用它一段时间之后答案可能是否定的,它在完成请求之前不会被删除,我想知道的是为什么。另外,我决定删除我的问题(关于原型)

3 个答案:

答案 0 :(得分:5)

你提出这样的问题是非常正确的:根据通常的Javascript内存管理,goGet以及随之而来的应该被垃圾收集。

但是,由于XMLHttpRequest是一种非常常见的使用模式,只是调用它而忘记它,因此在这些情况下有一些特殊的规则可以阻止它的垃圾收集。

规范在这里说: http://xhr.spec.whatwg.org/#garbage-collection

  

4.2垃圾收集

     

如果状态为XMLHttpRequest对象,则不得对其进行垃圾回收   OPENED和send()标志置位,其状态为HEADERS_RECEIVED,或   其状态为LOADING,并且已注册一个或多个事件侦听器   其类型是readystatechange,progress,abort,error,load,   超时和loadend。

     

如果XMLHttpRequest对象在其连接时被垃圾收集   仍处于打开状态,用户代理必须终止请求。

此处:http://www.w3.org/TR/XMLHttpRequest/#garbage-collection(措辞略有不同)。

在实践中,似乎某些实现可能实际上使XMLHttpRequest的时间长得多。您将在此处找到关于该主题的长时间讨论: http://nullprogram.com/blog/2013/02/08/

答案 1 :(得分:2)

goGet无法生存,但您的XmlHttpRequest实例

简单的答案是,在goGet电话结束时getForm 被垃圾收集,您将无法使用goGet访问任何内容在那之后。但是,这只是一个临时保存对内存中对象的引用的变量,XmlHttpRequest的实例用于触发post。由于下一步,实例结构本身仍将保留在内存中。

内部浏览器进程也是代码,并将保留引用

当您致电post - 仍在getFormgoGet存在时 - 您将存储的XHR设置为启动,这会触发内部浏览器进程处理这些请求,但仅限于在goGet完成执行后。因为XHR总是在执行调用它们的代码执行后触发,所以浏览器必须让它们特别“活着”以便它们实际工作。

因为XHR对象保持活动状态,所以你已经定义的readystatechange处理程序也会继续踢,这是一个闭包,它通过self将引用保存到XmlHttpRequest的原始实例。 / p>

虽然XHR请求仍在处理,但readystatechange处理程序仍然存在,因此使用XmlHttpRequest创建的整个结构将保持活动状态,直到此闭包被销毁。

有关此过程的信息性帖子可在此处找到:

http://nullprogram.com/blog/2013/02/08/

  

还应该注意的是,垃圾收集往往不是即时的,它通常发生在预定的波浪中,因此即使删除了对结构的所有引用,它仍然可以在内存中存在一段未知的时间。但是,在这种情况下,这不是保持结构存活的原因。

答案 2 :(得分:1)

XMLHttpRequests的W3C规范明确规定在某些情况下不能对XMLHttpRequest进行垃圾收集,如[XMLHttpRequest Level 1](http://www.w3.org/TR/XMLHttpRequest/)中所述。

因此,浏览器有责任确保不会在例如垃圾收集中进行垃圾收集。打开XMLHttpRequests。在没有深入了解细节的情况下,我注意到Chromes堆快照工具显示即使在本地引用超出范围之后,请求也被许多全局对象引用。多年来,与XMLHttpRequests内存泄漏有关的错误也有很多,我认为这可能是由于浏览器实现不正确。

  

4.3垃圾收集

     

如果状态为 XMLHttpRequest 对象,则不得对其进行垃圾回收   已打开并且发送()标志已设置,其状态为 HEADERS_RECEIVED ,或者   其状态为 LOADING ,以下之一为真:

     

它有一个或多个已注册的类型的事件侦听器    readystatechange 进度中止错误加载超时< / em>,或 loadend

     

上传完成标志未设置且已关联   XMLHttpRequestUpload对象已注册一个或多个事件侦听器   其类型进度中止错误加载超时 loadend

     

如果XMLHttpRequest对象在其连接时被垃圾收集   仍处于打开状态,用户代理必须终止请求。