Bug Tracker

Opened 11 years ago

Closed 11 years ago

Last modified 11 years ago

#12325 closed enhancement (wontfix)

Options parameter for $.when() to provide alternative semantics

Reported by: hippietrail Owned by:
Priority: undecided Milestone: None
Component: unfiled Version: 1.8.0
Keywords: Cc:
Blocked by: Blocking:


Currently $.when() has only one way of operating:

Wait until all Deferred's have been resolved or one has been rejected.

But there seem to be use cases for it to operate in other ways.

Some people want:

Wait until all Deferred's have been either resolved or rejected. (stackoverflow), (jquery bugs)

Others want:

Wait until one Deferred has been resolved. (stackoverflow), (stackoverflow)

And one more is:

Wait until all Deferred's have been rejected. (stackoverflow)

Do you see any merit in adding an "options" or "semantics" parameter to $.when() to allow the caller to specify these alternative behaviours? It could be as simple as this:

$.when( d1, d2, d3, {
  resolves: 'first',
  rejects: 'all'
  // do stuff

(I guess you'd like to see a plugin first, but so far I'm not good enough at jQuery for that. In the meantime I'm interested in what others think of this proposal.)

Change History (2)

comment:1 Changed 11 years ago by jaubourg

Resolution: wontfix
Status: newclosed

There are several problems with this approach.

The first, most obvious, one is that you effectively forbid the use of when with an object that contains properties named resolves or rejects (when will promote such an object to a resolved Promise with the object itself as the resolve value).

So, if you want this new functionality, put it in a new helper.

The second one is a matter of semantics and predictability. I'll take your first example here: waiting when all deferred are either resolved or rejected.

How do you differentiate between resolve and rejection values when they are in the same arguments list?

    $.Deferred().resolveWith( null, [ 1, 2, 3 ] ),
    $.Deferred().rejectWith( null, [ 4, 5, 6 ] )
).done(function( resolveValues, rejectValues ) {
    // How do I know what was resolved and what was rejected?

The only solution is to keep track of Deferreds in local variables:

var defer1 = $.Deferred().resolveWith( null, [ 1, 2, 3 ] ),
    defer2 = $.Deferred().rejectWith( null, [ 4, 5, 6 ] );

$.whenResolvedOrRejected( defer1, defer2 ).done(function( resolveValues, rejectValues ) {
    defer1.state() === "resolved";
    defer2.state() === "rejected";

That's simply an horrible approach.

To me, it's a typical case of Promise "re-routing":

function resolveAlways( promise ) {
    return promise.then(function() {
        return Deferred.resolveWith( this, [ "resolved" ].concat( arguments );
    }, function() {
        return Deferred.resolveWith( this, [ "rejected" ].concat( arguments );

    resolveAlways( $.Deferred().resolveWith( null, [ 1, 2, 3 ] ) ),
    resolveAlways( $.Deferred().rejectWith( null, [ 4, 5, 6 ] ) )
).done(function( resolveValues, rejectValues ) {
    resolveValues == [ "resolved", 1, 2, 3 ];
    rejectValues == [ "rejected", 4, 5, 6 ];

(I know arguments need to transformed into an array, but you get the idea)

Anyway, $.when is equivalent to a logical AND. I think that, if people need other kinds of operators, they should create new helpers, not mess with $.when to the point it doesn't make sense anymore.

I'd be glad to add such helpers into ajaxHooks ( https://github.com/jaubourg/ajaxHooks ), since adding new Promise helpers was my intention all along... except I just can't find the time to even maintain what's already in there :(

comment:2 Changed 11 years ago by jaubourg

Ah, also, if you need more advanced/flexible synchros. You're probably better off with something like fence that'll abort non-completed ajax requests in case of rejection. See https://github.com/jaubourg/fence/blob/master/doc/intro.md#introduction-to-fence

Again, I still have to find time to write the damn API doc.

Note: See TracTickets for help on using tickets.