Friday, June 19th, 2009
Serial Asynchronous XmlHttpRequests
<p>By default we should always favour asynchronous XHR to help the responsiveness of our Web applications. However, have you ever wanted a way to serialize your XHR calls because you needed to do things in sequence as B relied on what came back from A?You could call a synchronous Ajax call, but that locks up the browser. Thibaud Lopez Schneider has written up his thoughts here showing the difference between synchronous Ajax:

and async calls with magic to serialize them:

He then went and created a simple example code generator at asynchronous.me. It is interesting to look at the code of the serialized version, and see that it doesn't do anything complex.... just passes in the next function to run as a callback:
-
-
function run() {
-
request1(function () {
-
request2(function () {
-
request3(function () {
-
done();
-
});
-
});
-
});
-
}
-
function request1(callback1) {
-
// request 1
-
print("request1");
-
var xmlHttpRequest1 = new XMLHttpRequest();
-
xmlHttpRequest1.open("GET", "something1?hello1", true);
-
xmlHttpRequest1.onreadystatechange = function () {
-
if (this.readyState == 4 && this.status == 200) {
-
// response 1
-
print("response1=" + this.responseText);
-
// continue execution in the callback
-
if (callback1) {
-
callback1();
-
}
-
}
-
};
-
xmlHttpRequest1.send();
-
}
-
function request2(callback2) {
-
// request 2
-
print("request2");
-
var xmlHttpRequest2 = new XMLHttpRequest();
-
xmlHttpRequest2.open("GET", "something2?hello2", true);
-
xmlHttpRequest2.onreadystatechange = function () {
-
if (this.readyState == 4 && this.status == 200) {
-
// response 2
-
print("response2=" + this.responseText);
-
// continue execution in the callback
-
if (callback2) {
-
callback2();
-
}
-
}
-
};
-
xmlHttpRequest2.send();
-
}
-
function request3(callback3) {
-
// request 3
-
print("request3");
-
var xmlHttpRequest3 = new XMLHttpRequest();
-
xmlHttpRequest3.open("GET", "something3?hello3", true);
-
xmlHttpRequest3.onreadystatechange = function () {
-
if (this.readyState == 4 && this.status == 200) {
-
// response 3
-
print("response3=" + this.responseText);
-
// continue execution in the callback
-
if (callback3) {
-
callback3();
-
}
-
}
-
};
-
xmlHttpRequest3.send();
-
}
-
function done() {
-
// end
-
print("done");
-
}
-
You can compare that approach to Dojo Deferred:
-
-
function run() {
-
request1().addCallback(request2).addCallback(request3).addCallback(done);
-
}
-
function request1() {
-
// request 1
-
print("request1");
-
var deferred = dojo.xhrGet({
-
url: "something1?hello1",
-
load: function (response) {
-
// response 1
-
print("response1=" + response);
-
}
-
});
-
return deferred;
-
}
-
function request2() {
-
// request 2
-
print("request2");
-
var deferred = dojo.xhrGet({
-
url: "something2?hello2",
-
load: function (response) {
-
// response 2
-
print("response2=" + response);
-
}
-
});
-
return deferred;
-
}
-
function request3() {
-
// request 3
-
print("request3");
-
var deferred = dojo.xhrGet({
-
url: "something3?hello3",
-
load: function (response) {
-
// response 3
-
print("response3=" + response);
-
}
-
});
-
return deferred;
-
}
-
function done() {
-
// end
-
print("done");
-
}
-
Related Content:











Continuations and coroutines FTW!
A queue system would be much simpler and better, imho.
To have multiple Ajax Requests being executed serialized (still asynchronously though, think “queue” and not “synchronized”) is not only important, but it is also absolutely 100% imperative for many reasons. One simple example can be imagined when having two requests serializing the form and sending it back, then the first request removes or adds elements to the form in some manners… KABOOM…!
.
I have previously written extensively about the subject here; http://ra-ajax.org/how-to-create-an-ajax-library-part-5-wrapping-the-xmlhttprequest-xhr-object.blog
And here; http://ra-ajax.org/how-to-create-an-ajax-library-part-7-the-ra-ajax-class.blog
.
Also sometimes (though more seldom) you wish to execute XHR requests synchronously, one example is when you embed a JavaScript file into the page as a result of a callback. Then you wish to make sure that JS file is finished “executing” before you reference objects and types within it.
.
The first one is quite interesting (advanced) in implementation, but still not anymore advanced then that most serious Ajax Frameworks have had support for it for months, and often years. Like for instance http://ra-ajax.org – Disclaimer; I work with Ra-Ajax, remember…
.
To see this in action try to expand multiple items here; http://ra-ajax.org/samples/Ajax-Forum-Starter-Kit.aspx – *VERY* fast…
.
The second one is easier, though in fact fewer (possibly because of not that much of a demand) Ajax Frameworks really needs this possibility, which though when implemented nicely will seriously increase your maneuverability in regards to features and such in both your applications and your framework. Since then you can embed advanced widgets in Ajax Callbacks as response to some Business Logic happening on the server…
.
The first one though is probably the most underestimated things of all times in regards to Ajax, and also the most important feature *ANY* Ajax Framework can give you, though few does in fact …
.
I think it’s nice of Ajaxian to finally start focusing on this now though …
.
But the knowledge about these subjects have been out there for years…!
.
May I suggest a little bit more focus on frameworks, solutions, architecture and (framework-)design and a little bit less focus on DHTML and bling…?
What if I dont want to print out on paper? Seriously, print(‘done’)? :)
For those of us living in DWR-land, it’s as easy as:
dwr.engine.beginBatch();
// Multiple Ajax calls go here
dwr.engine.endBatch();
You get the callbacks firing in the order you made the Ajax calls (which of course, thanks to DWR, look just like JavaScript function calls) and as an added bonus, you get only a single request made to the server (although it could be hitting multiple objects on the server).
I’ve said it before and I’ll say it again: if you’re doing Java-based Ajax work and not using DWR, up the dosage my friend :)
“I’ve said it before and I’ll say it again: if you’re doing Java-based Ajax work and not using DWR, up the dosage my friend :)”
yeah, you’re the smart one out here. hopefully you’ve said enough and not find a need to say it again.
but is possiblle also using setTimeout with sync call ajax:
seTimeout(function() {
var res1=$.ajax({url:”http://1″,async:false});
var res2=$.ajax({url:”http://2″,async:false});
var res3=$.ajax({url:”http://3″,async:false});
},0);
Hi Dion,
I stumbled on a library, called Flapjax, for reactive programming which makes this kind of pattern easy. The basic idea is that instead of using a callback model for coding reactive patterns, you chain functions on an event stream abstraction.
In this instance you would write something like this pseudo-code:
triggerEventStream.CallXHR(call1).CallXHR(call2).CallXHR(call3).
If you want to trigger it only once, you can have triggerEventStream be a stream with a single event.
I haven’t used that library yet, but the event stream abstraction seems really useful. It can also be used to handle reacting to UI events.
Here’s a good tutorial which explains how a naive Flapjax implementation might work: http://www.weaselhat.com/2007/08/11/lifting-in-flapjax/
@andrewwell: That’s a pretty obnoxious reply on your part, don’t you think? Why the need for sarcasm there? If you’re not a fan of DWR, no problem… if you’re sick of me expressing how good a project I think it is, just ignore me… If you don’t agree with the sentiment, I’m all for a respectful discourse on the subject. But I see no point in being glib.
1. Synchronous XHR is not simply a bad idea; it’s a wildly unacceptable design that should be stricken from existence, and certainly never used. It’s fundamentally impossible to implement it within a browser under Javascript’s threading model (or lack thereof), in a way that doesn’t blow.
2. This is decidedly not a good idea for performance the way it’s described. If you need to make “multiple requests”, have all the necessary information at one point in time, but need to serialize them, then what you have is a single request. Otherwise, you’re just slowing everything down by creating unnecessary HTTP connections.
Vaadin (previously IT Mill Toolkit) also does this internally, although the implementation is a bit more complex than the simple example shown – as someone noted above, there are many cases to consider, e.g user clicks Button A and Button B in quick succession, but Button A removes Button B. You want to be as asynchronous as possible, but not asynchronousier ;-)
that’s a good pattern to remember, anyway