I have two promises, independent of each other and I want to do a finally step after both of the promises are completed (either rejects or resolves).
$q.all() cannot be used as I want the finally to always execute (only once for both promises) even if any of the promises rejects
One solution could be to have a counter and have a finallyHandler function to execute it when both promises resolves/rejects.
var count = 0;
function finallyHandler() {
if ( ++count === 2 ) {
doStuff();
count = 0;
}
}
firstPromise.finally(finallyHandler);
secondPromise.finally(finallyHandler);
This can work but doesn't look right.
Is there any better way to do this?
Promise.all(iterable) will do what you're looking for. Please have a look at the browser compatibility, however, as Internet Exploer does NOT support this method. From the documentation:
The Promise.all(iterable) method returns a promise that resolves when
all of the promises in the iterable argument have resolved, or rejects
with the reason of the first passed promise that rejects.
Using your code example (with failure behavior), it would look like this:
Promise.all([firstPromise, secondPromise]).then(values => {
finallyHandler();
}, reason => {
finallyHandler();
});
Even though the failure block is the same as the success block, the success block only runs once all promises have completed successfully, and the failure block runs once (and only once) the first failure is encountered.
Reference:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
Normally $q.all resolves rejected on the first promise that gets rejected and doesn't wait for the other promises. To wait for all promise to resolve either fulfilled or rejected, make resiliant versions of each promise, then use $q.all on those:
var resiliantFirstPromise = firstPromise.catch(e => "CONVERTED");
var resiliantSecondPromise = secondPromise.catch(e => "CONVERTED");
$q.all([resiliantFirstPromise, resiliantSecondPromise])
.then(() => {
console.log("Both promises have resolved");
});
By returning a value to the .catch method, each promise that is rejected returns a derived promise that has been converted to a fulfilled promise. Since neither derived promise is rejected, the $q.all will wait for both promises to be resolved (either fulfilled or rejected.)
firstPromise().catch().secondPromise().catch().then(//what you want)
The above promise chain can achieve this. Final then would be called in all scenarios . catch would propagate the promise rejections.
Can you use?
Promise.All([array of promises],handler)
Promise.All Docs
Or libraries like BlueBird or Asyncjs?
Related
I'm getting confused with the different terminology thrown around. From my understanding, a promise can be:
fulfilled
rejected
pending
settled
resolved
defer
Does resolve mean settled? or does it mean its fulfilled? and what the heck is defer?
Terminology can be hard.
Let's take from the Promises/A+ specification and the respective ES6 section that there are 3 states:
pending - the promise does not have taken a value yet, it's future is still uncertain.
fulfilled - the promise successfully got a result value "assigned"
rejected - the promise is given a reason why no result could be acquired, typically an error.
The term settled is a hyperonym for fulfilled and rejected, meaning either - the opposite of pending.
The dynamic verbs fulfill and reject describe changing the state from pending into either the fulfilled or rejected. These transitions are called fulfillment or rejection of the promise.
Those were easy. Now, resolve is a different beast. It sometimes is used synonymous to "fulfill", but it would better be understood as settling the promise's fate to either fulfilled or rejected. The resolution (seldom: settlement) of a promise means that it leaves the pending state. But not even that is accurate - the problem is the recursive nature of the Promise Resolution Procedure:
resolving a promise with a "plain" value means fulfilling it
resolving a promise with a promise (or thenable) means adopting its state:
resolving with a fulfilled promise is a fulfillment
resolving with a rejected promise is a rejection
resolving with a pending promise means waiting for its resolution
Yes, if a promise is resolved it might not even be known whether it's going to be fulfilled or rejected. But it means the fate is no longer undetermined, as it's bound to the promise that we resolved with (notice that you can resolve a promise only once).
Ignoring this special case, a resolved promise usually means a settled promise.
Or, to cite the ECMAScript 6 Specification:
A promise is resolved if it is settled or if it has been “locked in” to match the state of another promise. Attempting to resolve or reject a resolved promise has no effect. A promise is unresolved if it is not resolved. An unresolved promise is always in the pending state. A resolved promise may be pending, fulfilled or rejected.
and what the heck is defer?
Deferring a result means that you return an (asynchronous) promise for the result, and not the result directly (synchronously). And also return a deferred rejection instead of throwing synchronously.
Notice that "defer" is also used in some libraries (Q) as the method name to construct a Deferred object - see this answer on The differences between Deferred, Promise and Future for a good explanation.
Oh, and never trust variable names: defer might as well be an abbreviated "deferredObject".
The three promise states are listed in section 2.1 of the Promises/A+ specification.
From the specification:
So here are each of the terms you asked about:
Pending is the initial promise state. The operation represented by the promise has not yet been filfilled or rejected.
Fulfilled is another of the three promise states. It means that the promise has been resolved and now has its resolved value. The operation represented by the promise has been completed successfully.
Rejected is another of the three promise states. It means that the promise has been rejected and now has its rejected reason. The operation represented by the promise failed to obtain a value and thus has a reason for failing to do so (typically an error code or error object, but it can be anything).
Settled is a term that means the promise is either fulfilled or rejected (e.g. it's not pending any more), but it is not a separate state just a descriptive term to indicate it is no longer pending.
Resolved is a term that is often used to mean the same as fulfilled, but the two are not exactly the same. A promise can be resolved with a value which leads to fulfillment or it can be resolved with a rejected promise (which leads to rejection of this promise) or it can be resolved with a pending promise (which means it will now be waiting on the eventual state of some other promise).
It's hard to say exactly what you mean by defer. Promises are often classified as deferred objects in that they are an object that represents an action and result that is deferred to the future (it will occur in the future). In some promises implementations, there are actually two types of objects, a deferred object and a promise object. The deferred object is a superset of the promise object. Both can observe when the action is resolved or rejected with .then() handlers. But, only the deferred object can actually change the state to resolved or rejected.
In jQuery, you can create a deferred object with $.Deferred(). In other implementations such as ES6 promises, you just have promise objects with a constructor callback that has reject and resolve functions. The world is presumably moving toward what ES6 will have.
jQuery example that uses a deferred object:
function delay(t) {
var defer = $.Deferred();
setTimeout(function() {
defer.resolve();
}, t);
return defer.promise()
}
delay(200).then(function() {
// run my delayed function now
doMyThing();
});
ES6 promise example:
function delay(t) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve();
}, t);
});
}
delay(200).then(function() {
// run my delayed function now
doMyThing();
});
Domenic Denicola's "States and Fates" is a good, pithy summary.
States:
a promise is fulfilled if promise.then(f) will call f "as soon as possible"
a promise is rejected if promise.then(undefined, r) will call r "as soon as possible"
a promise is pending if it is neither fulfilled nor rejected.
Fates:
a promise is resolved if trying to resolve or reject it has no effect, i.e. the promise has been "locked in" to either follow another promise, or has been fulfilled or rejected
a promise is unresolved if it is not resolved, i.e. if trying to resolve or reject it will have an impact on the promise.
Follow the link for details 'relating states and fates'.
So I am wondering if this works?
S3.getObject()
.promise()
.then()
.catch() // catch error from the first then() statement
.then()
.catch() // catch error from the second then() statement
or do I need to place all 'catches' in the end? Can I have multiple catch then? Will they be fired in the order of the 'then' statements throwing errors?
It depends of your actual goals.
As a matter of fact, .then() method takes two parameters:
onFullfilled: Callback to be invoked when the promise is fulfilled.
onRejected: Callback to be invoked when the promise is rejected.
In fact, .catch(fn) is just a shorthand for .then(null, fn).
Both .then() and .catch() each return a new promise which resolves to its return value. In other words:
A resolved promise of that value if it isn't a promise.
The actual return value if it is already a promise (that will be fulfilled or rejected).
A rejected promise if the return value is a rejected promise (as previous point says) or any error is thrown.
The main reason behind the use of .then(onFullfill).catch(onReject) pattern instead of .then(onFullfill, onReject) is that, in the former (which is equivalent to .then(onFullfill).then(null, onReject)), we are chaining the onReject callback to the promise returned by first .then() instead of directly to the original promise.
The consequence of this is that if en error is thrown inside the onFullfill callback (or it returns a promise which happen to resolve to a rejected state), it will be catched by the chained .catch() too.
So, answering to your question, when you do something like:
P.then(...)
.then(...)
.then(...)
.catch(...)
;
You are chaining promises "supposing" all will go fine "and only check at the end". That is: Whenever any step fails, all subsequent .then()s are bypassed up to the next (in this case the last) .catch().
On the other hand, if you insert more .catch()s in between, you would be able to intercept rejected promises earlier and, if appropriate, solve whatever were going on and turn it into a resolved state again in order to resume the chain.
According to MDN:
If any of the passed in promises rejects, the all Promise immediately rejects with the value of the promise that rejected, discarding all the other promises whether or not they have resolved.
The ES6 spec seems to confirm this.
My question is: Why does Promise.all discard promises if any of them reject, since I would expect it to wait for "all" promises to settle, and what exactly does "discard" mean? (It's hard to tell what "discard" means for in-flight promises vs. promises that may not have run yet.)
I ask because I frequently run into situations where I have a list of promises and want to wait for them all to settle and get all rejections that may have occurred, which Promise.all doesn't cater to. Instead, I have to use a hack like this:
const promises = []; // Array of promises
const settle = promise => promise.then(result => ({ result }), reason => ({ reason }));
Promise.all(promises.map(settle))
.then(/ * check "reason" property in each element for rejection */);
Because Promise.all guarantees they all succeeded. Simple as that.
It's the most useful building block along with Promise.race. Everything else can be built on those.
There's no settle, because it's so trivial to build like this:
Promise.all([a(), b(), c()].map(p => p.catch(e => e)))
There's no easy way to build Promise.all on top of settle, which may be why it's not the default. settle would also have had to standardize a way to distinguish success values from errors, which may be subjective and depend on the situation.
Update: There's now a Promise.allSettled that does exactly this.
The asynchronous operations associated with the promises are all run. If one of those promises rejects, then Promise.all() simply does not wait for all of them to complete, it rejects when the first promise rejects. That is just how it was designed to work. If you need different logic (like you want to wait for all of them to be done, no matter whether they fulfill or reject), then you can't use just Promise.all().
Remember, a promise is not the async operation itself. A promise is just an object that keeps track of the state of the async operation. So, when you pass an array of promises to Promise.all(), all those async operations have already been started and are all in-flight already. They won't be stopped or cancelled.
Why does Promise.all discard promises if any of them reject, since I would expect it to wait for "all" promises to settle.
It works the way it does because that's how it was designed and that is a very common use case when you don't want your code to continue if there was any sort of error. If it happens to not be your use case, then you need to use some implementation of .settle() which has the behavior you want (which you seem to already know).
What I find the more interesting question is why is there not a .settle() option in the specification and standard implementation since it is also a fairly common use case. Fortunately, as you have found, it is not a lot of code to make your own. When I don't need the actual reject reason and just want some indicator value to be placed into the array, I often use this fairly simple to use version:
// settle all promises. For rejeted promises, return a specific rejectVal that is
// distinguishable from your successful return values (often null or 0 or "" or {})
Promise.settleVal = function(rejectVal, promises) {
return Promise.all(promises.map(function(p) {
// make sure any values or foreign promises are wrapped in a promise
return Promise.resolve(p).catch(function(err) {
// instead of rejection, just return the rejectVal (often null or 0 or "" or {})
return rejectVal;
});
}));
};
// sample usage:
Promise.settleVal(null, someArrayOfPromises).then(function(results) {
results.forEach(function(r) {
// log successful ones
if (r !== null) {
console.log(r);
}
});
});
what exactly does "discard" mean?
It just means that the promises are no longer tracked by Promise.all(). The async operations they are associated with keep right on doing whatever they were going to do. And, in fact if those promises have .then() handlers on them, they will be called just as they normally would. discard does seem like an unfortunate term to use here. Nothing happens other than Promise.all() stops paying attention to them.
FYI, if I want a more robust version of .settle() that keeps track of all results and reject reasons, then I use this:
// ES6 version of settle that returns an instanceof Error for promises that rejected
Promise.settle = function(promises) {
return Promise.all(promises.map(function(p) {
// make sure any values or foreign promises are wrapped in a promise
return Promise.resolve(p).catch(function(err) {
// make sure error is wrapped in Error object so we can reliably detect which promises rejected
if (err instanceof Error) {
return err;
} else {
var errObject = new Error();
errObject.rejectErr = err;
return errObject;
}
});
}));
}
// usage
Promise.settle(someArrayOfPromises).then(function(results) {
results.forEach(function(r) {
if (r instanceof Error) {
console.log("reject reason", r.rejectErr);
} else {
// fulfilled value
console.log("fulfilled value:", r);
}
});
});
This resolves to an array of results. If a result is instanceof Error, then it was a rejected, otherwise it's a fulfilled value.
I'd argue, because rejecting a promise is like throwing an error in sync code, and an uncatched error in sync code also interrupts the execution.
Or one could argue for the assumption that requesting all these promises and composing them into a combined Array, and then waiting for all these to finish implies that you need them all to proceed with whatever you've intended to do, and if one of them fails your intended task lacks one of its dependencies, and it is logical to simply forward the reason for the fail till this reason is somehow handled/caught.
I noticed something very strange happening when an exception is thrown inside a chain of promises in Parse for React Native. The promise chain never resolves, and never rejects, and the exception is never thrown. It just disappears silently.
Here's sample code to recreate the problem:
// Replacing this with Promise.resolve() prints the error.
// Removing this stage prints the error.
Parse.Promise.as()
// Removing this stage causes a red screen error.
.then(function() {
// Replacing this with Parse.Promise.as() causes a red screen error.
return Promise.resolve();
})
.then(function () {
throw new Error("There was a failure");
})
.then(function () { console.log("Success")}, function (err) { console.log(err) });
As you can see from the comments, it only seems to happen in this particular sequence of events. Removing a stage, or swapping a Parse promise for a native JS promise, causes things to behave again. (In my actual code, the "Promise.resolve()" stage is actually a call into a native iOS method that returns a promise.)
I'm aware that Parse promises don't behave exactly like A+ compliant promises (cf. https://stackoverflow.com/a/31223217/2397068). Indeed, calling Parse.Promise.enableAPlusCompliant() before this section of code causes the exception to be caught and printed. But I thought that Parse promises and native JS promises could be used together safely.
Why is this exception disappearing silently?
Thank you.
Why is this exception disappearing?
Parse does by default not catch exceptions, and promises do swallow them.
Parse is not 100% Promises/A+ compatible, but nonetheless it does try to assimilate thenables that are returned from then callbacks. And it does neither catch exceptions nor executes its own callbacks asynchronously.
What you are doing can be reproduced without then using
var p1 = new Parse.Promise();
var p2 = new Parse.Promise();
// p2 should eventually settle and call these:
p2._resolvedCallbacks = [function (res) { console.log("Success") }];
p2._rejectedCallbacks = [function (err) { console.log(err) }];
function handler() {
throw new Error("There was a failure");
}
// this is what the second `then` call sets up (much simplified):
p1._resolvedCallbacks = [function(result) {
p2.resolve(handler(result)); // throws - oops
}];
// the native promise:
var p = Promise.resolve();
// what happens when a callback result is assimilated:
if (isThenable(p))
p.then(function(result) {
p1.resolve(result);
});
The problem is that p1.resolve is synchronous, and executes the callbacks on p1 immediately - which in turn does throw. By throwing before p2.resolve can be called, p2 will stay forever pending. The exceptions bubbles up and becomes the completion of p1.resolve() - which now throws in a callback to a native then method. The native promise implementation catches the exception and rejects the promise returned by then with it, which is however ignored everywhere.
silently?
If your "native" promise implementation supports unhandled rejection warnings, you should be able to see the exception hanging around in the rejected promise.
For your consideration in addition to technical reasons provided in your quoted answer:
Compliant promises
ES6/A+ compliant Promise instances share:
When a promise is settled, its settled state and value are immutable.
A promise cannot be fulfilled with a promise.
A then registered 'fulfill' listener is never called with a promise (or other thenable) object as argument.
Listeners registered by then are executed asynchronously in their own thread after the code which caused them to be executed has run to completion.
Irrespective of whether a listener was registered for call back whan a promise becomes settled ( 'fulfilled' or 'rejected'),
the return value of a listener is used to fulfill resolve the promise returned by its then registration
a value thrown (using throw) by a listener is used to reject the promise returned by then registration, and
A promise resolved with a Promise instance synchronizes itself with the eventual settled state and value of the promise provided as argument. (In the ES6 standard this is described as "locked in").
A promise resolved with a thenable object which is not a Promise instance will skip synch as required: if at first resolved with a thenable which "fulfills" itself with a thenable, the Promise promise will re-synchronize itself with the most recent 'thenable' provided. Skipping to a new thenable to synchronize with cannot occur with A+ promises because they never call a "fulfilled" listener with a thenable object.
Non Compliant promises
Potential characteristics of non compliant promise like objects include
allowing the settled state of a promise to be changed,
calling a then 'fulfilled' listener with a promise argument,
calling a then listener, either for 'fulfilled' or 'rejected' states, synchronously from code which resolves or rejects a promise,
not rejecting a then returned promise after a listener registered in the then call throws an exception.
Interoperability
Promise.resolve can be used to settle its returned promise with a static value, perhaps mainly used in testing. Its chief purpose, however, is to quarantine side effects of non compliant promises. A promise returned by Promise.resolve( thenable) will exhibit all of behaviours 1-7 above, and none of the non compliant behaviours.
IMHO I would suggest only using non A+ promise objects in the environment and in accordance with documentation for the library which created them. A non compliant thenable can be used to to resolve an A+ promise directly (which is what Promise.resolve does), but for full predictability of behaviour it should be wrapped in a Promise object using Promise.resolve( thenable) before any other use.
Note I tried to test Parse promises for A+ compliance but it does not seem to provide a constructor. This makes claims of "almost" or "fully" A+ compliance difficult to quantify. Thanks to zangw for pointing out the possibility of returning a rejected promise form a listener as an alternative to throwing an exception.
I'm getting confused with the different terminology thrown around. From my understanding, a promise can be:
fulfilled
rejected
pending
settled
resolved
defer
Does resolve mean settled? or does it mean its fulfilled? and what the heck is defer?
Terminology can be hard.
Let's take from the Promises/A+ specification and the respective ES6 section that there are 3 states:
pending - the promise does not have taken a value yet, it's future is still uncertain.
fulfilled - the promise successfully got a result value "assigned"
rejected - the promise is given a reason why no result could be acquired, typically an error.
The term settled is a hyperonym for fulfilled and rejected, meaning either - the opposite of pending.
The dynamic verbs fulfill and reject describe changing the state from pending into either the fulfilled or rejected. These transitions are called fulfillment or rejection of the promise.
Those were easy. Now, resolve is a different beast. It sometimes is used synonymous to "fulfill", but it would better be understood as settling the promise's fate to either fulfilled or rejected. The resolution (seldom: settlement) of a promise means that it leaves the pending state. But not even that is accurate - the problem is the recursive nature of the Promise Resolution Procedure:
resolving a promise with a "plain" value means fulfilling it
resolving a promise with a promise (or thenable) means adopting its state:
resolving with a fulfilled promise is a fulfillment
resolving with a rejected promise is a rejection
resolving with a pending promise means waiting for its resolution
Yes, if a promise is resolved it might not even be known whether it's going to be fulfilled or rejected. But it means the fate is no longer undetermined, as it's bound to the promise that we resolved with (notice that you can resolve a promise only once).
Ignoring this special case, a resolved promise usually means a settled promise.
Or, to cite the ECMAScript 6 Specification:
A promise is resolved if it is settled or if it has been “locked in” to match the state of another promise. Attempting to resolve or reject a resolved promise has no effect. A promise is unresolved if it is not resolved. An unresolved promise is always in the pending state. A resolved promise may be pending, fulfilled or rejected.
and what the heck is defer?
Deferring a result means that you return an (asynchronous) promise for the result, and not the result directly (synchronously). And also return a deferred rejection instead of throwing synchronously.
Notice that "defer" is also used in some libraries (Q) as the method name to construct a Deferred object - see this answer on The differences between Deferred, Promise and Future for a good explanation.
Oh, and never trust variable names: defer might as well be an abbreviated "deferredObject".
The three promise states are listed in section 2.1 of the Promises/A+ specification.
From the specification:
So here are each of the terms you asked about:
Pending is the initial promise state. The operation represented by the promise has not yet been filfilled or rejected.
Fulfilled is another of the three promise states. It means that the promise has been resolved and now has its resolved value. The operation represented by the promise has been completed successfully.
Rejected is another of the three promise states. It means that the promise has been rejected and now has its rejected reason. The operation represented by the promise failed to obtain a value and thus has a reason for failing to do so (typically an error code or error object, but it can be anything).
Settled is a term that means the promise is either fulfilled or rejected (e.g. it's not pending any more), but it is not a separate state just a descriptive term to indicate it is no longer pending.
Resolved is a term that is often used to mean the same as fulfilled, but the two are not exactly the same. A promise can be resolved with a value which leads to fulfillment or it can be resolved with a rejected promise (which leads to rejection of this promise) or it can be resolved with a pending promise (which means it will now be waiting on the eventual state of some other promise).
It's hard to say exactly what you mean by defer. Promises are often classified as deferred objects in that they are an object that represents an action and result that is deferred to the future (it will occur in the future). In some promises implementations, there are actually two types of objects, a deferred object and a promise object. The deferred object is a superset of the promise object. Both can observe when the action is resolved or rejected with .then() handlers. But, only the deferred object can actually change the state to resolved or rejected.
In jQuery, you can create a deferred object with $.Deferred(). In other implementations such as ES6 promises, you just have promise objects with a constructor callback that has reject and resolve functions. The world is presumably moving toward what ES6 will have.
jQuery example that uses a deferred object:
function delay(t) {
var defer = $.Deferred();
setTimeout(function() {
defer.resolve();
}, t);
return defer.promise()
}
delay(200).then(function() {
// run my delayed function now
doMyThing();
});
ES6 promise example:
function delay(t) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve();
}, t);
});
}
delay(200).then(function() {
// run my delayed function now
doMyThing();
});
Domenic Denicola's "States and Fates" is a good, pithy summary.
States:
a promise is fulfilled if promise.then(f) will call f "as soon as possible"
a promise is rejected if promise.then(undefined, r) will call r "as soon as possible"
a promise is pending if it is neither fulfilled nor rejected.
Fates:
a promise is resolved if trying to resolve or reject it has no effect, i.e. the promise has been "locked in" to either follow another promise, or has been fulfilled or rejected
a promise is unresolved if it is not resolved, i.e. if trying to resolve or reject it will have an impact on the promise.
Follow the link for details 'relating states and fates'.