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()
保持某种全局联系)?
编辑:我觉得在使用它一段时间之后答案可能是否定的,它在完成请求之前不会被删除,我想知道的是为什么。另外,我决定删除我的问题(关于原型)
答案 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
电话结束时getForm
被垃圾收集,您将无法使用goGet
访问任何内容在那之后。但是,这只是一个临时保存对内存中对象的引用的变量,XmlHttpRequest
的实例用于触发post
。由于下一步,实例结构本身仍将保留在内存中。
当您致电post
- 仍在getForm
且goGet
存在时 - 您将存储的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对象在其连接时被垃圾收集 仍处于打开状态,用户代理必须终止请求。