Reputation: 771
I am trying to use deferred and promises within the context of a loop and I fail doing so.
I need to call a first method asynchronously. This first method (let´s call it getArray()) returns an array.
For each element of the array, I need to call a second method, let´s call it getData(id). The id is stored in the array returned by getArray.
Finally, once I have the result of getData(), I need to use the result to call a third method, let´s call it getDetails().
Once all the calls are done and the loop is finished, I need to return the array, with extra data and details.
I created a jsfiddle: http://jsfiddle.net/chevdor/953sLkts/
var myarray = [];
var log = function(s){
$('#console').append('<p>'+s+'</p>');
};
var get1 = function() {
var dfd = jQuery.Deferred();
log('Running get1');
setTimeout(function() {
var res = [1, 2, 3, 4];
// that´s probably crap...
for (var i= 0; i< res.length; i++){
get2(res[i])
.done(get3(res[i])
.done(get4(res[i]))
);
}
dfd.resolve(res);
}, Math.floor(400 + Math.random() * 1000));
return dfd.promise();
};
var get2 = function(index) {
var dfd = jQuery.Deferred();
log('Running get2');
setTimeout(function() {
var res = {
index: index,
val: index * 2
};
myarray[index]= res;
dfd.resolve(res);
}, Math.floor(400 + Math.random() * 1000));
return dfd.promise();
};
var get3 = function(index) {
var dfd = jQuery.Deferred();
log('Running get3');
setTimeout(function() {
var res = {
index: index,
val2: index * index
};
myarray[index].extra = res;
dfd.resolve(res);
}, Math.floor(400 + Math.random() * 1000));
return dfd.promise();
};
var get4 = function(index) {
var dfd = jQuery.Deferred();
log('Running get4');
setTimeout(function() { // Resolve after a random interval
var res = {
index: index,
val2: index * index
};
dfd.resolve(res);
}, Math.floor(400 + Math.random() * 1000));
return dfd.promise();
};
log('start');
get1();
to illustrate. It definitely does not work and look ugly...
Can you explain what would be the proper way to do that?
Upvotes: 0
Views: 1386
Reputation: 1072
May I introduce you to $.when.
From your code, it looks like your get2(), get3(), get4() are the getData(), getDetail(). Assume they all are made like a promise. Then you can do this:
getArray().then(function(array){
var allpromises=_.map(array,function(one){
var toReturn={id:one}
// let's assume the array is [1,2,3...]; then one= 1,2,3...
return getData(one).then(function(onedata){
//onedata={name:'foo',id:1} just an example.
toReturn['data']=onedata;
return getDetail(onedata);
}).then(function(detail){ // here you get detail
toReturn['detail']=detail;
return jQuery.resolve(toReturn);
});
});
return jQuery.when(allpromises); // This is a promise, resolves when every promise in the array all resolved. the resolved data is the same length array (same length as the allpromises.
}).then(function(dataarray){
console.log(dataarray); //each entry should be like the "toReturn". {id:1,data:{name:'foo',id:1},detail:{object}}
})
I was a big fan of bluebird promise, the keyword was .all() instead of .when(). I am not exactly sure how jquery promise work, but I believe it is a very similar structure. Hope this helps. Let me know if it is unclear :)
EDIT: Sorry for the confusion, to use $.when on array of promises, the syntax is:
$.when.apply($, [promise1,promise2,promise3]).then(function(data){
})
Note the "data" here is only the resolved from promise1, I am not familiar with jquery. But I do recommend bluebird promise. Which is faster and cleaner.
Upvotes: 1
Reputation: 1
Try creating an array p
, .push()
results of $.when(get2(res[i]), get3(res[i]), get4(res[i]))
to p
; call $.when.apply
with p
as array of jQuery promise objects passed ; check results of dfd.resolve(res)
, myarray
at .then
onFulfilled
handler of get1
var myarray = [];
var log = function(s){
$('#console').append('<p>'+s+'</p>');
};
var get1 = function() {
var dfd = jQuery.Deferred();
log('Running get1');
var p = [];
setTimeout(function() {
var res = [1, 2, 3, 4];
// that´s probably crap...
for (var i= 0; i< res.length; i++){
p.push($.when(get2(res[i]), get3(res[i])
, get4(res[i])))
};
$.when.apply($, p).then(function() {
dfd.resolve($.makeArray(arguments))
})
}, Math.floor(400 + Math.random() * 1000));
return dfd.promise();
};
var get2 = function(index) {
var dfd = jQuery.Deferred();
log('Running get2');
setTimeout(function() {
var res = {
index: index,
val: index * 2
};
myarray[index]= res;
dfd.resolve(res);
}, Math.floor(400 + Math.random() * 1000));
return dfd.promise();
};
var get3 = function(index) {
var dfd = jQuery.Deferred();
log('Running get3');
setTimeout(function() {
var res = {
index: index,
val2: index * index
};
myarray[index] = {"extra":res};
dfd.resolve(res);
}, Math.floor(400 + Math.random() * 1000));
return dfd.promise();
};
var get4 = function(index) {
var dfd = jQuery.Deferred();
log('Running get4');
setTimeout(function() { // Resolve after a random interval
var res = {
index: index,
val2: index * index
};
dfd.resolve(res);
}, Math.floor(400 + Math.random() * 1000));
return dfd.promise();
};
log('start');
get1().then(function() {
console.log("res:", arguments, "myarray:", myarray);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<h1>Test</h1>
<span id='console'></span>
jsfiddle http://jsfiddle.net/953sLkts/9/
Upvotes: 0