If you're looking for something like:
Send request A
when A returns,
Send request B(result a)
when B returns,
Do C(response b)
Then you need to make each one a promise, and you need to pay attention to closures (because you can't collect the return value from a callback).
a_done = something_that_returns_a_promise();
a_done.then(function (a_result) {
var b_done = something_that_returns_a_promise(a_result);
b_done.then(function (b_result) { do_C(b_result); });
});
If you're looking for something like
Send request A
Send request B
when A && B return,
Do C
Then you're looking at a function which will take a number of promises, and return a promise.
a = something_returning_a_promise();
b = something_returning_a_promise();
a_and_b_done = when(a, b);
a_and_b_done.then(function (result1, result2) { do_c(result1, result2); })
.then(show_results);
Doing something like
a_done.then(fillRows).then(showResults);
Doesn't let you make multiple async calls... ...what it does is allows you to chain a bunch of synchronous tasks one after the other (or make async calls where the order they arrive in doesn't matter at all).
.then
or
.done
or whatever, doesn't do anything special -- it adds a task to an array.
When the async promise returns (or if it's already returned and has been resolved), it just goes through that list in order, and fires all of the callbacks, passing whatever data it was resolved with (and calling the "success" or "failure" callbacks, based on the success of the operation).
So you need one promise for each async callback, and if you're trying to chain callbacks together, you still need to wrap each one inside of a closure (the closure which will pass the result to whatever is constructing your next promise).
I'm using the jQuery $.Deferred()
, deferred.promise()
, deferred.resolve()
, deferred.reject()
, promise.done()
, promise.fail()
and $.when()
here:
other libraries might have different terminology, but will behave similarly.
var ImageLoader = function (name, format) {
var loading = $.Deferred(),
img = new Image(),
url = name + (format || ".png");
img.onload = function () {
loading.resolve(img);
};
img.onerror = function () {
loading.reject("Image failed to load:" + name);
};
img.src = url;
return loading.promise();
};
var imgLoaded = ImageLoader("//mysite.com/myimg");
imgLoaded.done(function () { console.log("img 1 loaded"); });
imgLoaded.fail(function (msg) { console.log(msg); });
var img2Loaded = ImageLoader("//yoursite.com/yourimg", ".jpg");
img2Loaded.done(function () { console.log("img 2 loaded"); });
img2Loaded.fail(function (msg) { console.log(msg); });
var showImages = function (img1, img2) {
document.body.appendChild(img1);
document.body.appendChild(img2);
};
var both_loaded = $.when(imgLoaded, img2Loaded);
both_loaded.done(showImages);
This is a messy and convoluted example, but rather than making it elegant, I figured I'd try to write it in a way that shows all of the pieces.