How to chain ajax requests?
Solution 1
Don't use anonymous functions. Give them names. I don't know if you're able to do what I wrote below though:
var step_3 = function() {
c.finish();
};
var step_2 = function(c, b) {
ajax(c(b.somedata), step_3);
};
var step_1 = function(b, a) {
ajax(b(a.somedata), step_2);
};
ajax(a, step_1);
Solution 2
You could have a single function which is passed an integer to state what step the request is in, then use a switch statement to figure out what request needs to be make next:
function ajaxQueue(step) {
switch(step) {
case 0: $.ajax({
type: "GET",
url: "/some/service",
complete: function() { ajaxQueue(1); }
}); break;
case 1: $.ajax({
type: "GET",
url: "/some/service",
complete: function() { ajaxQueue(2); }
}); break;
case 2: $.ajax({
type: "GET",
url: "/some/service",
complete: function() { alert('Done!'); }
}); break;
}
}
ajaxQueue(0);
Hope that helps!
Solution 3
This function should chain together a list of ajax requests, if the callbacks always return the parameters necessary for the next request:
function chainajax(params, callbacks) {
var cb = shift(callbacks);
params.complete = function() {
var newparams = cb(arguments);
if (callbacks)
chainajax(newparams, callbacks);
};
$.ajax(params);
};
You can define these callback functions separately and then chain them together:
function a(data) {
...
return {type: "GET", url: "/step2.php?foo"}
};
// ...
function d(data) { alert("done!"); };
chainajax({type: "GET", url: "/step1.php"},
[a, b, c, d]);
You could also declare the functions "inline" in the call to chainajax, but that might get a little confusing.
Solution 4
Maybe what you can do is write a server-side wrapper function. That way your javascript only does a single asynchronous call to your own web server. Then your web server uses curl (or urllib, etc.) to interact with the remote API.
Solution 5
Update: I've learn a better answer for this if you are using jQuery, see my update under the title: Using jQuery Deffered
Old answer:
You can also use Array.reduceRight
(when it's available) to wrap the $.ajax
calls and transform a list like: [resource1, resource2]
into $.ajax({url:resource1,success: function(...) { $ajax({url: resource2...
(a trick that I've learn from Haskell and it's fold/foldRight function).
Here is an example:
var withResources = function(resources, callback) {
var responses = [];
var chainedAjaxCalls = resources.reduceRight(function(previousValue, currentValue, index, array) {
return function() {
$.ajax({url: currentValue, success: function(data) {
responses.push(data);
previousValue();
}})
}
}, function() { callback.apply(null, responses); });
chainedAjaxCalls();
};
Then you can use:
withResources(['/api/resource1', '/api/resource2'], function(response1, response2) {
// called only if the ajax call is successful with resource1 and resource2
});
Using jQuery Deffered
If you are using jQuery, you can take advantage of jQuery Deffered, by using the jQuery.when()
function:
jQuery.when($.get('/api/one'), $.get('/api/two'))
.done(function(result1, result2) {
/* one and two is done */
});
defnull
Updated on June 22, 2022Comments
-
defnull almost 2 years
I have to interact with a remote api that forces me to chain requests. Thats a callback-hell in asynchronous mode:
// pseudocode: ajax(request_object, callback) ajax(a, function() { ajax(b(a.somedata), function() { ajax(c(b.somedata), function() { c.finish() } }) })
It would be much more readable in sync mode:
sjax(a) sjax(b(a.somedata)) sjax(c(b.somedata)) c.finish()
But Sjax is evil :) How do I do that in a
nicenot-so-evil and readable way?