Reputation: 2474
I have an application where I'm pulling data from multiple sources, and only when all the data is pulled in, do I want to continue. I want the data as fast as possible so use parallel requests.
To figure out when all requests are done, I'm doing this:
function getData(cb) {
var count, data;
count = 0;
data = {};
function getDataDone() {
count++;
//only call callback when all async requests are done
if (count === 3 && cb) {
cb(data);
}
}
foo.doAsync({
success: function (d) {
data.foo = d;
getDataDone();
}
});
bar.doAsync({
success: function (d) {
data.bar = d;
getDataDone();
}
});
$.getJSON("/api/", function (d) {
data.user = d;
getDataDone();
});
} //end getData
getData(function (data) {
//application data loaded, do stuff
data.foo;
data.bar;
data.user;
});
foo.doAsync
, bar.doAsync
and $.getJSON
requests happen is parallel, when completed, they call getDataDone()
, which increments a counter. If the counter is equal to the expected number of requests, run callback.
How might jQuery.deferred be applied in this case? To code works perfectly OK as it is. Is there any benefit to using deferred over what I have?
Upvotes: 3
Views: 948
Reputation: 15104
Using jQuery.when: http://api.jquery.com/jQuery.when/ you can wait for several promises to finish.
You could wrap your doAsync()
methods in promises.
function doAsync (opts) {
var msg = this.msg;
var data = { json: JSON.stringify({ msg: msg }) };
$.ajax("/echo/json/", {
type: "post",
data: data
}).then(opts.success);
}
var foo = { msg: "foo", doAsync: doAsync };
var bar = { msg: "bar", doAsync: doAsync };
function createPromise (doAsyncAble) {
var dfd = $.Deferred();
doAsyncAble.doAsync({
success: function (d) {
dfd.resolve(d);
}
});
return dfd.promise();
}
function getData(cb) {
var fooPromise = createPromise(foo);
var barPromise = createPromise(bar);
var apiPromise = $.ajax("/echo/json/", {
type: "post",
data: { json: JSON.stringify({ data: "api" }) }
});
$.when(fooPromise, barPromise, apiPromise).done(function (fooResponse, barResponse, apiResponse) {
var data = {};
data.foo = fooResponse;
data.bar = barResponse;
data.user = apiResponse[0];
cb(data);
});
} //end getData
getData(function (data) {
console.log(data);
});
Produces:
You could also return a promise from getData rather than passing in a callback.
Upvotes: 1
Reputation: 254926
var d1 = $.Deferred();
foo.doAsync({
success: function (d) {
data.foo = d;
d1.resolve();
}
});
var d2 = $.Deferred();
bar.doAsync({
success: function (d) {
data.bar = d;
d2.resolve();
}
});
var json_deferred = $.getJSON("/api/", function (d) {
data.user = d;
getDataDone();
});
$.when(d1, d2, json_deferred).then(function() {
alert('all requests finished');
});
Is there any benefit to using deferred over what I have?
Yep, deferreds allow more control on the app flow and usually (this case isn't an exception) provide more clear solutions.
Hint: if you only need the result of asynchronous requests in the callback and nothing else - you may pass the result to the resolve
call like d1.resolve(d);
and then get it as a parameter of then()
callback, instead of using shared object as a temporary storage.
In case of getJSON()
you could even omit the callback:
var json_deferred = $.getJSON('/api/');
Upvotes: 4