$.Deferred: How to Detect When Every Promise Has Been Executed

$.Deferred: How to detect when every promise has been executed

More sophisticated promise libraries have an allSettled() function like Q or Promise.settle like Bluebird.

In jQuery, you could implement such a function yourself as well and extend the $ namespace with it, but that will only be necessary if you need it often and performance-optimized.

A simpler solution would be to create a new promise for each of the ones you are waiting for, and fulfilling them even when the underlying one is rejected. Then you can use $.when() on them without problems. In short:

// using Underscore's .invoke() method:
$.when.apply(null, _.invoke(promises, "then", null, $.when)).done(…)

More stable:

$.when.apply($, $.map(promises, function(p) {
return p.then(null, function() {
return $.Deferred().resolveWith(this, arguments);
});
})).then(…);

You might change the then callbacks a bit to distinguish between fulfilled and rejected results in the final done.

How to determine if Javascript Q deferred() has executed all the functions in the chain

Yes, there is! Heck - I'd go as far as to say that it is the whole point of promises.

That method is called drumroll .then!

When using it, we'll also use Q.all in order to wait for a collection of promises. This is because you have a loop. If you didn't - all we'd need is .then

function testJSCallbacks(){
var promises = [];
for(var i = 0; i < 5; i++){
...
promise = promise.then(function (key) {
//Log the output of step here
console.log("Step 1 " + key);
return key;
})
//then function takes a callback function with one parammeter (the data).
//foo signature meets this criteria and will use the resolution of the last promise (key).
.then(foo)
//myCB will execute after foo resolves its promise, which it does in the onsuccess callback
.then(myCB);
promises[i] = promise;
}
return Q.all(promises); // note the return statement
}

Then, you can hook on its completion:

 testJSCallbacks().then(function(results){
// everything is complete and none of it rejected
});

If you take one thing from this post - it should be to return promises from methods :). Also, instead of running myCb simply return the value and run myCb from the outside - it's more powerful :)

Building an array of deferred functions (promises)?

The promise executor function (the callback you pass to new Promise()) is designed to be executed immediately, thus you will see all your console.log() statements immediately.

What usually happens in the executor is that you start some async operation such as an ajax request or an async file I/O request and then some time later, that request will call resolve(xxx) to resolve that promise with a value. What you have now has no async operations, never calls resolve() and really should not be using promises at all since there is no asynchronous activity here.

A promise is not a function. It is not "executed". So, you don't really create an array of deferred functions with promises like your question implies. You could use promises to keep track of some asynchronous operations and you could execute some functions when those promises resolved by attaching listeners to the promise, but you don't really execute promises.

To make a promise that you're creating work, you supply the function that executes as the promise executor callback passed to new Promise(fn). That's where the executing happens. The promise itself is just an object that serves as a placeholder for a future value of some asynchronous operation. The promise value is set when code in the executor calls resolve(someValue). Or, an error can be indicated by calling reject(someError). Meanwhile code outside the executor function can then register listeners with .then() or .catch() to listen for a state change in the promise (some future time when the promise fulfills to a value or ends with an error).

So, right after either resolve() or reject() is called, the appropriate event listeners (that were registered with .then() or with .catch()) will trigger, informing the listening code that there is finally a resolution to this promise (either a value or an error). That listening code can then process that value or error.

Promise.all() accepts an array of promises and returns a new master promise that is rejected when any of the array of promises rejects or is resolved with an array of values when all the array of promises are resolved. It watches all those other promises and essentially gives you a summary of them all.

To simulate an async operation, we could put all your operations inside a setTimeout() and then call resolve() like this runnable snippet:

 var buildPromises = function (numbers) {     var res = [];     numbers.forEach(function (num) {         var p = new Promise(function (resolve, reject) {             // this is called immediately and it starts             // an asynchronous operation that will finish later             setTimeout(function () {                 var result = num * 2;                 console.log("individual:", result);                 // resolve the promise with our result                 resolve(result);             }, Math.floor(Math.random() * 500) + 500);         });         res.push(p);     });     return Promise.all(res); }
var numbers = [1, 2, 3, 4, 5]; buildPromises(numbers).then(function (results) { console.log("group: ", JSON.stringify(results)); });

How can I determine if a jQuery object is deferred?

Depending on your use case, you could also use jQuery.when [1]:

If a single argument is passed to jQuery.when and it is not a Deferred, it will be treated as a resolved Deferred and any doneCallbacks attached will be executed immediately.

With jQuery.when you can treat your mysterious object always as deferred:

// x could be a deferred object or an immediate result
var x = getMysteriousObject();
// success will be called when x is a deferred object and has been resolved
// or when x is an immediate result
jQuery.when( x ).then( success, error );

[1] http://api.jquery.com/jQuery.when/



Related Topics



Leave a reply



Submit