0

I don't understand where is the problem, I've read several questions here, but nothing something like that. I can't use a function to return a promise, I need just tu put all the promises in one array and pass it to the "$.when" function.

var pr = [];
var count = 3; 
while(count--){
   setTimeout(function(){ 
     var def = $.Deferred();
     pr.push(def.promise());    
     console.log('COUNT: '+count); def.resolve(count); 
   }, Math.random()*2000);
}  

$.when.apply($, pr).done(function(d){
     console.log("LOG:",d);
});

Obviously doesn't work because in WHEN pr is empty by that time. How can sort it out?

Donovant
  • 3,091
  • 8
  • 40
  • 68
  • You need to create the deferreds immediately (so that you can pass them into `$.when`), not somewhen in the future! – Bergi Jan 26 '17 at 13:54

1 Answers1

2

You're only adding the deferreds to the array after they've run. The point is you want them in the array up front and then when they all resolve execute some functionality.

var defA = $.Deferred();
var pr = [defA.promise()];
var count = 3; 

var defB = $.Deferred();
pr.push(defB.promise());     
    
var defC = $.Deferred();
pr.push(defC.promise());     
    

setTimeout(function(){ 
    console.log('COUNT: '+count--); defB.resolve(count); 

}, Math.random()*2000);

setTimeout(function(){ 
    console.log('COUNT: '+count--); defC.resolve(count); 
    defA.resolve(11011);
}, Math.random()*2000);


$.when.apply($, pr).done(function(d){
     console.log("LOG:",d);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

For your update, you'll need to also use a closure, as count will have changed by the time the async work has completed (ie, without it you'll get logged count: 0 three times). This closure also has the neat side effect of keeping def in local scope for each iteration. More info in this Q/A: JavaScript closure inside loops – simple practical example

var pr = [];
var count = 3; 
while(count--){
   
   (function(x){
       var def = $.Deferred();
       pr.push(def.promise());    
       setTimeout(function(){        
        
          console.log('COUNT: '+ x); 
          def.resolve(x); 
       }, Math.random()*2000);
     
   })(count);
}  

$.when.apply($, pr).done(function(){
     console.log("LOG:",arguments);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

EDIT - changed the callback to when so that you can see that, even though they resolve in a random order, you get the results back in the order they went in. (ie aruments[0] will always be 2 even though that one possibly didnt resolve first)

Community
  • 1
  • 1
Jamiec
  • 133,658
  • 13
  • 134
  • 193
  • How can I do that if I create $.Deferred in a while/for/each? – Donovant Jan 26 '17 at 13:06
  • @Donovant asking the right question is a good start. Dont ask `a` if you're question is really `b`. But, whether they are in a line or a loop, shouldnt make a difference. Create the deferrd outside of the async work it's doing. – Jamiec Jan 26 '17 at 13:06
  • 1
    @Donovant I assume you didnt intend to `count--` twice? – Jamiec Jan 26 '17 at 13:34
  • @Donovant answer updated. It is a little more complex with a loop, but only just. – Jamiec Jan 26 '17 at 13:44