1

I'm using

$.when.apply($, arrayOfDeferreds).then(function() {
  var args = Array.prototype.slice.call(arguments);
  var anotherArrayOfDeferreds = [];

  args.map(function(item){
      anotherArrayOfDeferreds.push(item.getSomething()); // item.getSomething() returns an deferred.
  });

  // return an anotherArrayOfDeferreds
});

to deal with an array of deferreds. However, in (do something here ...) above, it generates another array of deferreds, which essentially needs another $.when.apply() and which cannot be dealt with by .then(). I am wondering if there is a way to chain $.when?

Thanks!

Yu Wu
  • 11
  • 2
  • _"it generates another array of deferreds, which essentially needs another $.when.apply() and which cannot be dealt with by .then()"_ Can create stacksnippets , jsfiddle http://jsfiddle.net to demonstrate ? – guest271314 Jun 23 '15 at 04:21

3 Answers3

1

I think you can pass it again to $.when to create a new promise which can be returned from the then to make it chainable

$.when.apply($, array).then(function () {
    var newarray = [];

    return $.when.apply($, newarray)
});
Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
  • I have tried this. But ... return $.when.apply($, newarray)}).then(callback); the callback does not get called ... – Yu Wu Jun 23 '15 at 04:19
  • @YuWu - your syntax for what you posted in your comment is not correct. It has an extra `})` in it. – jfriend00 Jun 23 '15 at 04:29
1

$.when() does not generate another array of deferreds. It returns a single promise that will be resolved when all the promises you passed it were resolved (or rejected if any of those promises are rejected).

The results passed to the single promise's resolved handler are an array of results. In some cases (like with $.ajax(), it will be an array of arrays of results).

So, what you had:

$.when.apply($, array).then(function(arrayOfResults) {
    (do something here ...)
});

Will work just fine for telling you when all the promises you passed to $.when() have finised. The code in the .then() handler will be passed an array of results and will only be called when all the promises you passed to $.when() have been resolved.

If, inside of the .then() handler, you want to start up N more async operations, you can just use $.when() again inside there. Or, you each of your original async calls wants to have it's own chained operation, then you should chain those before passing them to $.when() so what is passed to $.when() is the result of chaining each individual chain.

For example, you could do this:

var p1 = $.ajax(...).then(...).then(...).then(...).then(...);
var p2 = $.ajax(...).then(...).then(...).then(...);

$.when(p1, p2).then(function(arrayOfResults) {
    // will be executed when all the chained operations in p1 and p2 are done
});

Or, you could do this for another series of parallel operations:

$.when.apply($, array).then(function(arrayOfResults) {
    // first up N more async operations
    return $.when.apply($, newArray).then(...);
});

If you want help beyond this, you will need to be much more specific about what your problem is. So far, it sounds like it could be handled by one of the circumstances above.


Based on your edited question, you could do this:

$.when.apply($, arrayOfDeferreds).then(function() {
  var args = Array.prototype.slice.call(arguments);

  var anotherArrayOfDeferreds = args.map(function(item){
      return item.getSomething(); // item.getSomething() returns an deferred.
  });
  $.when.apply($, anotherArrayOfDeferreds).then(function() {
      // called when this new array of deferreds is done
  });

});

But, this is a bit of an unusual structure. Usually, if there are more async operations to be performed after an async operation, you don't resolve and pass an item that can then be used on a later async operation, but rather you just chain the async operation right where you've got it.

So, rather than doing this inside your original async operation:

d.resolve(item);

which you must be using now, you'd do this:

return item.getSomething();

This would just chain the next async operation onto the previous one and your original $.when() would work for all.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Sorry I didn't make it clear in the description. In (do something here ...), I generated an array of deferreds, which need to use $.when.apply to handle. But I tried the method offerred by Arun P Johny, the callback in .then() didn't get called. – Yu Wu Jun 23 '15 at 04:26
  • @YuWu - then you're not doing it correctly. `$.when()` works for an array of deferreds or promises. It works. If it doesn't work for you, then it's because you aren't using it properly and you will need to show us your actual code so we can help you see what you're not doing correctly. The theoretical discussion is done. We now need to see your actual code that you say doesn't work. – jfriend00 Jun 23 '15 at 04:27
  • @jfriend00 Perhaps OP is attempting to describe an array of actual deferred objects being returned to next `.then()` ? – guest271314 Jun 23 '15 at 04:30
  • 1
    @guest271314 - could be - that's one possible guess. But at this point, the theoretical discussion is done because we know `$.when()` works so this is a problem with how the OP is trying to use it. We need to see the actual OP's code. – jfriend00 Jun 23 '15 at 04:33
  • @guest271314 thanks! What you described was exactly what I want to ask. – Yu Wu Jun 23 '15 at 04:39
  • @YuWu - You're likely doing something wrong if you're getting a list of deferreds back as the result from `$.when()`. That would mean somebody is called `.resolve()` and passing it a new deferred. That seems screwy to me. It should be chained directly to that promise, not resolved with another promise. All would be clear IF WE COULD SEE YOUR ACTUAL CODE. Sorry for the shouting, but we do get kind of tired of trying to GUESS what the actual code is doing. It's a very, very, very slow way to solve a problem. – jfriend00 Jun 23 '15 at 04:40
  • @jfriend00 thanks for your answer and comments. The code needs significant amount of setup, which is impossible to post here or jsfiddle. But I edited the code in my description, which is essentially what the actual code does. – Yu Wu Jun 23 '15 at 04:46
  • Thank you very much @jfriend00! I modified my code according to your suggestions and it now works! – Yu Wu Jun 23 '15 at 05:21
0

Firstly, let's call them promises not deferreds, because there's no need ever to do this sort of thing with deferreds.

Now, assuming you don't need the promise returned by $.when.apply(arrayOfPromises) for any other purpose, then a double $.when() is unnecessary.

You can map arrayOfPromises to another array of promises and do a single $.when.apply() on that array.

$.when.apply($, arrayOfPromises.map(function(promise) {
    return promise.then(function(item) {
        return item.getSomething();
    });
})).then(function() {
    var resultsOfTheDualAsyncProcesses = Array.prototype.slice.call(arguments);
});

DEMO

Roamer-1888
  • 19,138
  • 5
  • 33
  • 44