Reputation: 5904
Bounty Note: Simple question is, why don't I need to worry about goGet
being removed before the request finished if it is an asynchronous request?
I have a form that is generated with PHP which produces many HTML rows I'll refer to as "Entries". Each Entry has two options, "Delete" and "Edit", each of which may need to create zero or more XMLHttpRequest
s.
To try to make handling requests manageable, I made a XmlHttpRequest
class, shown below:
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);
}
When either Delete or Edit are clicked they call functions, one of which is this:
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;
}
This appears to work just fine. However, after writing this I became worried that when executions ends in getForm()
that it may be possible for goGet
to be removed before the request finished and the process would not complete within function XmlHttpRequest()
, this.request.onreadystatechange = function()
.
Is this something I need to be worried about (and so I have to maintain some kind of global connection to each goGet
)?
Edit: I realize at this point after using it for a while that the answer is probably no, it somehow is not removed before it finished the request, what I want to know is why. Also, I decided to remove my side question (about the prototype)
Upvotes: 1
Views: 340
Reputation: 3315
The W3C specification for XMLHttpRequests specifically states that the XMLHttpRequest can not be garbage collected under certain circumstances as explained in [XMLHttpRequest Level 1] (http://www.w3.org/TR/XMLHttpRequest/).
It is thus the responsibility of the browser to ensure that garbage collection does not take place on e.g. open XMLHttpRequests. Without looking deeper into the details, I have noticed that Chromes Heap Snapshot tool shows that the request is referenced by a number of global objects even after a local reference has gone out of scope. There have also been a number of bugs over the years relating to memory leaks with XMLHttpRequests, which I think was likely due to browser implementations not getting this right.
4.3 Garbage collection
An XMLHttpRequest object must not be garbage collected if its state is OPENED and the send() flag is set, its state is HEADERS_RECEIVED, or its state is LOADING, and one of the following is true:
It has one or more event listeners registered whose type is readystatechange, progress, abort, error, load, timeout, or loadend.
The upload complete flag is unset and the associated XMLHttpRequestUpload object has one or more event listeners registered whose type is progress, abort, error, load, timeout, or loadend.
If an XMLHttpRequest object is garbage collected while its connection is still open, the user agent must terminate the request.
Upvotes: 1
Reputation: 36035
The simple answer is that goGet
is garbage collected at the end of the getForm
call, you won't be able to access anything using goGet
after that point. However, this was just a variable that temporarily held a reference to an object in memory, an instance of XmlHttpRequest
, which was used to trigger post
. The instance structure itself will still remain in memory because of the next step.
At the point you call post
— still within getForm
and while goGet
exists — you set the stored XHR going, which triggers the internal browser process for handling these requests, but only after goGet
has finished execution. Because XHRs always trigger after the execution of the code that called them into existence the browser has to keep them specially "alive" in order for them to actually work.
Because the XHR object is kept alive, your already defined readystatechange
handler is also kept kicking, which is a closure, that holds a reference — via self — to your original instance of XmlHttpRequest
.
Whilst the XHR request is still processing the readystatechange
handler will still exist, and so the entire structure you have created using XmlHttpRequest
will be kept alive, until this closure is destroyed.
An informative post about this process can be found here:
http://nullprogram.com/blog/2013/02/08/
It should be also noted that garbage collection doesn't tend to be instantaneous, it usually happens in scheduled waves, so even if all references to a structure are removed, it can still sit around in memory for a unknown period of time. However, in this instance, this is not what is keeping your structure alive.
Upvotes: 2
Reputation: 17710
You are quite right to ask the question: according to the usual Javascript memory management, goGet and all that goes with it should be garbage-collected.
However, since it's a pretty common use pattern of XMLHttpRequest
to just invoke it and forget about it, there are special rules preventing its garbage collection in these cases.
The specs says so here: http://xhr.spec.whatwg.org/#garbage-collection
4.2 Garbage collection
An XMLHttpRequest object must not be garbage collected if its state is OPENED and the send() flag is set, its state is HEADERS_RECEIVED, or its state is LOADING and it has one or more event listeners registered whose type is one of readystatechange, progress, abort, error, load, timeout, and loadend.
If an XMLHttpRequest object is garbage collected while its connection is still open, the user agent must terminate the request.
Also here: http://www.w3.org/TR/XMLHttpRequest/#garbage-collection (slightly different wording).
In practice, it seems some implementations may actually keep the XMLHttpRequest
s a lot longer that that. You'll find a long discussion on the topic here:
http://nullprogram.com/blog/2013/02/08/
Upvotes: 6