patternjavascriptMinor
Multiple jQuery promises
Viewed 0 times
promisesjquerymultiple
Problem
I'm starting to reuse this pattern, and was wondering if there was a more succinct/clear way to write it.
Given a function
And function
I'm quite happy with the pattern, but the
Given a function
foo taking a callback argument:function foo(..., cb) { ... }And function
bar which calls foo with several different arguments taking a callback function of its own to be called when all the 'dependent' callbacks have been called, I write:function bar(data, cb) {
var promises = [];
function createPromise() {
var p = $.Deferred();
promises.push(p);
return function() { p.resolve(); };
};
for (var i = 0; i < data.length; i++) {
foo(data[i], createPromise());
}
$.when.apply($, promises).then(cb);
}I'm quite happy with the pattern, but the
apply and closure-returning-a-function make me suspect that there might be a simpler way of doing the same... Ideas?Solution
Well, first of all, your closure doesn't have to create a function. This will work just as well:
Second of all, if you're doing this pattern a lot, I would make a generic method that lets you convert any function that accepts a callback to one that returns a promise:
A slightly less-readable version can eliminate the
function createPromise() {
var p = $.Deferred();
promises.push(p);
return p.resolve; // Doesn't create an anonymous function
};Second of all, if you're doing this pattern a lot, I would make a generic method that lets you convert any function that accepts a callback to one that returns a promise:
function callbackToPromise(func) {
return function() {
var args = $.makeArray(arguments);
var p = $.Deferred();
args.push(p.resolve); // Add the deferred as a callback
func.apply(this, args);
return p.promise();
};
}
var improvedFoo = callbackToPromise(foo);
function bar(data, cb) {
var promises = [];
for (var i = 0; i < data.length; i++) {
promises.push(improvedFoo(data[i]));
}
$.when.apply($, promises).then(cb);
}$.when really should accept an array of Deferred's as an argument, but until that feature is added, I don't think there's a way to avoid using .apply here, except to add another helper function: function when(promises) {
return $.when.apply($, promises);
}
function bar(data, cb) {
var promises = [];
for (var i = 0; i < data.length; i++) {
promises.push(improvedFoo(data[i]));
}
when(promises).then(cb);
}A slightly less-readable version can eliminate the
promises variable entirely, though I prefer the more-readable version above:function bar(data, cb) {
when($.map($.makeArray(data), function(item) {
return improvedFoo(item);
})).then(cb);
}Code Snippets
function createPromise() {
var p = $.Deferred();
promises.push(p);
return p.resolve; // Doesn't create an anonymous function
};function callbackToPromise(func) {
return function() {
var args = $.makeArray(arguments);
var p = $.Deferred();
args.push(p.resolve); // Add the deferred as a callback
func.apply(this, args);
return p.promise();
};
}
var improvedFoo = callbackToPromise(foo);
function bar(data, cb) {
var promises = [];
for (var i = 0; i < data.length; i++) {
promises.push(improvedFoo(data[i]));
}
$.when.apply($, promises).then(cb);
}function when(promises) {
return $.when.apply($, promises);
}
function bar(data, cb) {
var promises = [];
for (var i = 0; i < data.length; i++) {
promises.push(improvedFoo(data[i]));
}
when(promises).then(cb);
}function bar(data, cb) {
when($.map($.makeArray(data), function(item) {
return improvedFoo(item);
})).then(cb);
}Context
StackExchange Code Review Q#8809, answer score: 3
Revisions (0)
No revisions yet.