Reputation: 3220
In Is JavaScript guaranteed to be single-threaded? it becomes clear that however javascript is single threaded there are still caveats.
I was wondering whether the following pseudo-code is always predictable (I'm 'using' jQuery)
var lastReq;
$('#button').click(function()
{
if (lastReq) lastReq.abort();
lastReq = $.ajax(...);
});
The case could be that between the click event and the abort, the data from the server came through and put an event on de eventqueue. If this happens just before the abort, the succes event of the ajax post would be triggered. I have no idea how to really test this possible race condition.
Does anyone have an idea how this works? Or how to test this with a prepped example?
Upvotes: 2
Views: 270
Reputation: 11
Edit: As soon as you abort the request, the browser shouldn't be listening for it any longer. So when it reaches the response in the event queue, my guess is it should just throw it out.
However, if you're having problems with it, you could try the following:
Could you do a check in your success function + url to cancel itself if it detects it no longer needs to be run?
For instance (and I'm not saying you should do it this way, I haven't tried attaching anything to the jqXHR request):
var numReq = 0, lastReq;
$('#button').on('click', function(e) {
if (lastReq) { lastReq.abort(); }
numReq ++;
lastReq = $.ajax({
success : function(d, s, x) {
if (x.reqNum < numReq) { return; }
}
});
lastReq.reqNum = numReq;
});
My understanding is the ajax event won't be added to the event queue until after the button click is done, so you shouldn't (theoretically) have to worry about setting the reqNum after the ajax ...
I've also tried the following code:
var numReq = 0, lastReq, timer = 100,
c = setInterval(function() {
if (lastReq) { lastReq.abort(); }
numReq ++;
lastReq = $.ajax({
url : 'index.html',
cache : false,
success : function(d, s, x) {
if (x.reqNum < numReq) { console.log('it happens'); }
}
});
lastReq.reqNum = numReq;
}, timer);
Varying the timer to try and match (as close as possible) the load time of the page. I haven't had "it happens" show up.
Upvotes: 1
Reputation: 123397
I don't know if this workaround could be really useful and be bullet-proof (I'm trying to be creative) but, since jQuery 1.5 ajax methods return a deferred object lastReq
have state()
method available
From http://api.jquery.com/deferred.state/
The deferred.state() method returns a string representing the current state of the Deferred object. The Deferred object can be in one of three states:
...
"resolved": The Deferred object is in the resolved state, meaning that either deferred.resolve() or deferred.resolveWith() has been called for the object and the doneCallbacks have been called (or are in the process of being called).
so you could refactor your code like so
var lastReq;
$('#button').click(function() {
if (lastReq) {
if (lastReq.state() === "resolved") {
return false; /* done() of the previous ajax call is in the process of
being called. Do nothing and wait until the state
is resolved */
}
else {
lastReq.abort();
}
}
lastReq = $.ajax(url).done(function() {
/* do something */
lastReq = null;
});
});
hope this could help to give you an idea to work on, but I suspect there's no really need of this kind of workaround
Upvotes: 1