Question

I have this code

$.when(
    // I checked the first one and assume all return promises
    datacontext.entity1.getPromise({ ...options... }),
    datacontext.entity2.getPromise({ ...options... }),
    datacontext.entity3.getPromise({ ...options... }),
    datacontext.entity4.getPromise({ ...options... }),
    datacontext.entity5.getPromise({ ...options... }),
    datacontext.entity6.getPromise({ ...options... }),
    datacontext.entity7.getPromise({ ...options... }),                    )
.then(
    // some more similar calls returning promises
    datacontext.entity8.getPromise({ ...options... }),
    datacontext.entity9.getPromise({ ...options... }),
    datacontext.entity10.getPromise({ ...options... }),
    datacontext.entity11.getPromise({ ...options... }),                    
)
.then(function() {
    // do work with the results
});

If I understand correctly, execution of first then() should not start until all defers in the when() have been resolved. Is that correct? Should I expect the same for the two then() sections - i.e. // do work with the results should not be reached before all calls from preceeding then() have resolved? It seems to be true in Chrome, but in FF I am hitting the last then() before all defers have been resolved.

So based on the comment, is this the right way to chain things?

$.when(
    // I checked the first one and assume all return promises
    datacontext.entity1.getPromise({ ...options... }),
    datacontext.entity2.getPromise({ ...options... }),
    datacontext.entity3.getPromise({ ...options... }),
    datacontext.entity4.getPromise({ ...options... }),
    datacontext.entity5.getPromise({ ...options... }),
    datacontext.entity6.getPromise({ ...options... }),
    datacontext.entity7.getPromise({ ...options... })
)
.then(function() {
    $.when(
        // some more similar calls returning promises
        datacontext.entity8.getPromise({ ...options... }),
        datacontext.entity9.getPromise({ ...options... }),
        datacontext.entity10.getPromise({ ...options... }),
        datacontext.entity11.getPromise({ ...options... })
    )
    .then(function() {
        // do work with the results
    });
})
Was it helpful?

Solution

In jQuery $.when (and Promise.all in the standard) takes a list of promises and returns a promises that resolves when all of the promises resolve.

The .then method signals continuation and accepts a fulfillment and rejection handler. When you a return a promise from a .then it will continue on only when the returned promise has resolved. When you return a value, it will continue "immediately".

So, what you want to do is to return a $.when from the second then handler:

$.when(
    // I checked the first one and assume all return promises
    datacontext.entity1.getPromise({ ...options... }),
    datacontext.entity2.getPromise({ ...options... }),
    datacontext.entity3.getPromise({ ...options... }),
    datacontext.entity4.getPromise({ ...options... }),
    datacontext.entity5.getPromise({ ...options... }),
    datacontext.entity6.getPromise({ ...options... }),
    datacontext.entity7.getPromise({ ...options... }))
.then(function(){ // our handler, note that its params are the resolution values

    return $.when( // which will resolve when this composite promise will resolve
    // some more similar calls returning promises
    datacontext.entity8.getPromise({ ...options... }),
    datacontext.entity9.getPromise({ ...options... }),
    datacontext.entity10.getPromise({ ...options... }),
    datacontext.entity11.getPromise({ ...options... }),                    
    )
})
.then(function() {
    // do work with the results
});

If I may suggest:

  1. Use a real promise implementation, jQuery deferred objects are very limited.
  2. Pass the data from the promise using the return value rather than using global/closure variables.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top