This question already has an answer here:
Let's say I have a Promise.all()
that handles two promises. If one promise produces an error, but the other resolves, I would like to be able to handle the errors based on the situation after the Promise.all()
has settled.
ES6 Promises are missing the settle method, I'm assuming for a good reason. But I can't help but think that the .settle()
method would make this problem a lot easier for me.
Am I going about this the wrong way or is extending the ES6 Promises with a settle method the right thing to do here?
An example of how I am thinking of using .settle()
:
Promise.all([Action1,Action2])
.settle(function(arrayOfSettledValues)
//if 1 failed but not 2, handle
//if 2 failed but not 1, handle
//etc....
)
You can't directly use
Promise.all()
to generate.settle()
type behavior that gets you all the results whether any reject or not becausePromise.all()
is "fast-fail" and returns as soon as the first promise rejects and it only returns that reject reason, none of the other results.So, something different is needed. Often times, the simplest way to solve that problem is by just adding a
.then()
handler to whatever operation creates your array of promises such that it catches any rejects and turns them into fulfilled promises with some specific value that you can test for. But, that type of solution is implementation dependent as it depends upon exactly what type of value you are returning so that isn't entirely generic.If you want a generic solution, then something like
.settle()
is quite useful.You can't use the structure:
Because
Promise.all()
rejects when the first promise you pass it rejects and it returns only that rejection. The.settle()
logic works like:And, if you're interested, here's a fairly simple implementation of
Promise.settle()
:In this implementation,
Promise.settle()
will always resolve (never reject) and it resolves with an array ofPromiseInspection
objects which allows you to test each individual result to see whether it resolved or rejected and what was the value or reason for each. It works by attaching a.then()
handler to each promise passed in that handles either the resolve or reject from that promise and puts the result into aPromiseInspection
object which then becomes the resolved value of the promise.You would then use this implementation like this;
FYI, I've written another version of
.settle
myself that I call.settleVal()
and I often find it easier to use when you don't need the actual reject reason, you just want to know if a given array slot was rejected or not. In this version, you pass in a default value that should be substituted for any rejected promise. Then, you just get a flat array of values returned and any that are set to the default value where rejected. For example, you can often pick arejectVal
ofnull
or0
or""
or{}
and it makes the results easier to deal with. Here's the function:And, then you use it like this:
This isn't an entire replacement for
.settle()
because sometimes you may want to know the actual reason it was rejected or you can't easily distinguish a rejected value from a non-rejected value. But, I find that more than 90% of the time, this is simpler to use.Here's my latest simplification for
.settle()
that leaves aninstanceof Error
in the return array as the means of distinguishing between resolved values and rejected errors:And, then you use it like this:
This can be a complete replacement for
.settle()
for all cases as long as aninstanceof Error
is never a resolved value of your promises (which it really shouldn't be).