ES6 Promise.all() error handle - Is .settle() needed? [duplicate] - javascript

This question already has answers here:
Wait until all promises complete even if some rejected
(20 answers)
Closed 6 years ago.
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....
)

Am I going about this the wrong way or is extending the ES6 Promises
with a settle method the right thing to do here?
You can't directly use Promise.all() to generate .settle() type behavior that gets you all the results whether any reject or not because Promise.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:
Promise.all([...]).settle(...).then(...);
Note (added in 2019): It appears the Promise standards effort has picked Promise.allSettled() as a standard implementation of "settle-like" behavior. You can see more on that at the end of this answer.
Because Promise.all() rejects when the first promise you pass it rejects and it returns only that rejection. The .settle() logic works like:
Promise.settle([...]).then(...);
And, if you're interested, here's a fairly simple implementation of Promise.settle():
// ES6 version of settle
Promise.settle = function(promises) {
function PromiseInspection(fulfilled, val) {
return {
isFulfilled: function() {
return fulfilled;
}, isRejected: function() {
return !fulfilled;
}, isPending: function() {
// PromiseInspection objects created here are never pending
return false;
}, value: function() {
if (!fulfilled) {
throw new Error("Can't call .value() on a promise that is not fulfilled");
}
return val;
}, reason: function() {
if (fulfilled) {
throw new Error("Can't call .reason() on a promise that is fulfilled");
}
return val;
}
};
}
return Promise.all(promises.map(function(p) {
// make sure any values are wrapped in a promise
return Promise.resolve(p).then(function(val) {
return new PromiseInspection(true, val);
}, function(err) {
return new PromiseInspection(false, err);
});
}));
}
In this implementation, Promise.settle() will always resolve (never reject) and it resolves with an array of PromiseInspection 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 a PromiseInspection object which then becomes the resolved value of the promise.
You would then use this implementation like this;
Promise.settle([...]).then(function(results) {
results.forEach(function(pi, index) {
if (pi.isFulfilled()) {
console.log("p[" + index + "] is fulfilled with value = ", pi.value());
} else {
console.log("p[" + index + "] is rejected with reasons = ", pi.reason());
}
});
});
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 a rejectVal of null or 0 or "" or {} and it makes the results easier to deal with. Here's the function:
// settle all promises. For rejected 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).then(null, function(err) {
// instead of rejection, just return the rejectVal (often null or 0 or "" or {})
return rejectVal;
});
}));
};
And, then you use it like this:
Promise.settleVal(null, [...]).then(function(results) {
results.forEach(function(pi, index) {
if (pi !== null) {
console.log("p[" + index + "] is fulfilled with value = ", pi);
}
});
});
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 an instanceof Error in the return array as the means of distinguishing between resolved values and rejected errors:
// settle all promises. For rejected promises, leave an Error object in the returned array
Promise.settleVal = 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) {
let returnVal = err;
// instead of rejection, leave the Error object in the array as the resolved value
// make sure the err is wrapped in an Error object if not already an Error object
if (!(err instanceof Error)) {
returnVal = new Error();
returnVal.data = err;
}
return returnVal;
});
}));
};
And, then you use it like this:
Promise.settleVal(null, [...]).then(function(results) {
results.forEach(function(item, index) {
if (item instanceof Error) {
console.log("p[" + index + "] rejected with error = ", item);
} else {
console.log("p[" + index + "] fulfilled with value = ", item);
}
});
});
This can be a complete replacement for .settle() for all cases as long as an instanceof Error is never a resolved value of your promises (which it really shouldn't be).
Promise Standards Effort
As of 2019, it appears that .allSettled() is becoming the standard for this type of behavior. And, here's a polyfill:
if (!Promise.allSettled) {
Promise.allSettled = function(promises) {
let wrappedPromises = Array.from(promises).map(p =>
this.resolve(p).then(
val => ({ state: 'fulfilled', value: val }),
err => ({ state: 'rejected', reason: err })
)
);
return this.all(wrappedPromises);
}
}
Usage would be like this:
let promises = [...]; // some array of promises, some of which may reject
Promise.allSettled(promises).then(results => {
for (let r of results) {
if (r.state === 'fulfilled') {
console.log('fulfilled:', r.val);
} else {
console.log('rejected:', r.err);
}
}
});
Note that Promise.allSettled() itself always resolves, never rejects though subsequent .then() handlers could throw or return a rejected promise to make the whole chain reject.
As of June 2019, this not yet in the current desktop Chrome browser, but is planned for an upcoming release (e.g. later in 2019).

Related

Javascript: In promises what is the purpose of resolve and reject?

As I understand it, resolve and reject are specified in the callback provided to the promise constructor and invoked within the callback. But resolve and reject (I think) always do the same thing, so why do they even have to be specified?
EDIT: I should clarify: I do not think that resolve does the same thing as reject; I mean resolve seems to always resolve and reject always reject -- is there a way to pass in a function instead of resolve that does something else?
EDIT: To further clarify as I did in a comment below: if a Promise constructor takes a function which in turn takes resolve and reject and these are always to be called in the function, why must resolve and reject be specified as arguments at all?
Final Edit: I tried with foo instead of resolve and it still worked. How can that be? I did not define foo at all?? I probably am not understanding something about javascript beyond promises. code snippet where i changed resolve to foo
When you create a JS Promise, you expect some task to happen asynchronously. It is possible, that this task can succeed or fail. The success and failure are defined based on what the task is.
When you create a new Promise, you as the creator must specify what to do when the task is successful or is a failure. To communicate the same to the consumer of the promise resolve/reject come handy.
So when the consumer uses a then to check the output of the promise. what ever is returned by resolve is given to the consumer.
When the consumer uses a catch to check the output of the promise. whatever is returned by the reject is given to the consumer.
import {Promise} from 'es6-promise'
const foo = true;
const bar = new Promise((resolve, reject) => {
if (foo) {
resolve(4);
} else {
reject(2);
}
})
bar.then((value) => console.log(value)).catch((value) => console.log(value));
you can run the above sample by changing the value of foo to true/false and see for yourself what the output is.
I assume you are referring to the then() function which takes two callbacks, one when the promise is resolved and one when it is resolved. The pattern often looks like this:
myPromise.then(result => {
// do something here
},
error => {
}
);
If the promise is resolved everything went as expected and the first callback should proceed as normal. If the promise is rejected the second callback should perform error handling, possibly displaying an appropriate message to the user. These never do the same thing.
If you have logic that should always occur, whether there is an error or not, you should chain another call to then():
myPromise.then(result => {
// do something here
},
error => {
// do something here
}
).then(result => {
// do something here
}
);
This is conceptually the same as try...catch...finally from many programming languages.
Resolve and reject do not "do the same thing".
When you resolve a promise you are saying "this is the successful response of this promise".
When you reject a promise you are saying "this promise failed because...".
For example:
Imagine in the following examples accountApiRequest() actually does an API request to fetch an account. If there is no account it will most likely return null or throw an exception.
When a promise is successful you will resolve it. When a promise is not successful it will be rejected.
Successful promise
function accountApiRequest() {
return {
id: 1234,
username: 'Jim',
}
}
function getAccount() {
return new Promise(function(resolve, reject) {
account = accountApiRequest()
if (!account) {
return reject('Unable to fetch account')
}
return resolve(account)
});
}
getAccount().then(console.log).catch(console.log)
Failed promise
function accountApiRequest() {
return null
}
function getAccount() {
return new Promise(function(resolve, reject) {
account = accountApiRequest()
if (!account) {
return reject('Unable to fetch account')
}
return resolve(account)
});
}
getAccount().then(console.log).catch(console.log)
In the Promise constructor we have a callback which takes the resolve and reject methods as its arguments. After a Promise is created using the constructor a Promise can have three states:
Pending
Resolved
Rejected
When a promise is resolved then the callback which is passed in the then() method is called. If the promise is rejected the callback which is passed in the catch() method is called. For example:
const prom = new Promise((resolve, reject) => {
setTimeout(() => {
if(Math.random() > 0.5) {
resolve('resolved');
} else {
reject('rejected');
}
}
, 2000)
});
prom.then((val) => console.log('succes: ' + val))
.catch((val) => console.log('fail: ' + val))
In our example the resolve or reject is called in a setTimeout, therefore the status of the promise is the first 2 seconds pending. After the setTimeout is expired the Promise is either resolved or rejected based on the value of Math.random(). Then either the then or the catch callback is executed to handle the result of the promise.
When the promise is rejected the callback passed in the catch method is called
When the promise is resolved the callback passed in the then method is called
I had the same question when I read about Promises. And I came to understanding that you don't need to define resolve and reject functions by yourself (they will be ignored and standard resolve/reject functions will be called anyway): I think of them as special functions which let you indicate whether to resolve or reject the promise by calling one of them; and what value to return in each case by passing arguments to these functions. It doesn't matter how you name them in promise constructor - first argument is resolve function and the second - reject.
I have spent a ton of time trying to figure this out. Unfortunately, for anyone well versed with JS syntax, won't really understand the question...
For me, it was clear, after unraveling the concise JS syntactic sugar:
function promise_executor(resolve_callback_provided_by_promise_instance, reject_callback_provided_by_promise_instance) {
if (<some_condition>) {
// success
var response='bla';
resolve_callback_provided_by_promise_instance(response);
} else {
// fail
var error=new Error('failed');
reject_callback_provided_by_promise_instance(error);
}
}
var promise_instance = new Promise(promise_executor);
So the reject and resolve are just random names for callbacks that the promise instance will call.
They have proper interfaces, like both will take 1 param of type object. That param will be passed to either the Promise.then() or the Promise.catch().
resolve
reject
Then, when you use them, it is like this:
function success_callback(param_from_resolve) {
console.log('success() ', param_from_resolve);
}
function fail_callback(param_from_reject) {
console.log('fail(): ', param_from_reject);
}
promise_instance
.then(success_callback) // this will be the var 'resolve' from above
.catch(fail_callback); // this will be the var 'error' from above
The whole code flow is like this:
<at some point, your promise_executor() code is called with 2 functions, as parameters>
// obviously, the promise_executor() function has its own name in the Promise object
promise_executor(Promise.reject, Promise.resolve);
<promise_executor() will -hopefully- call either the resolve or the reject callback, which will in turn trigger either the callback of then() or catch()>
<say we have then()>
<the Promise code will take the response param from resolve_callback_provided_by_promise_instance(response) and give it to the callback from then()>
param_from_resolve(response)
It will go down something like this (THIS IS NOT what actually happens, as in reality, the micro-queue, the eventloop, etc. gets involved - this is a linearized version of the gist of what is happening):
What you see:
var promise = new Promise(promise_executor);
What is executed:
function Promise.constructor(exec_callback_fnc) {
var this = object();
this.exec_callback_fnc = exec_callback_fnc; // this is "promise_executor"
return this;
}
What you see:
// at some point in "this.exec_callback_fnc":
resolve_callback_provided_by_promise_instance(response)
What is executed:
function promise_instance.resolve(param) {
this.param_from_resolve = param;
promise_instance.resolved = true;
}
What you see:
promise_instance
.then(success_callback)
What is executed:
promise_instance.exec_callback_fnc(promise_instance.resolve, promise_instance.reject);
if (promise_instance.resolved) {
function promise_instance.then(callback_fnc) {
callback_fnc(this.param_from_resolve); // this is "success_callback"
}
}
Finally, let's see, how the syntax makes this whole thing more concise:
function promise_executor(resolve_callback_provided_by_promise_instance,
reject_callback_provided_by_promise_instance) {
if (<some_condition>) {
// success
var response='bla';
resolve_callback_provided_by_promise_instance(response);
} else {
// fail
var error=new Error('failed');
reject_callback_provided_by_promise_instance(error);
}
}
var promise_instance = new Promise(promise_executor);
function success_callback(param_from_resolve) {
console.log('success() ', param_from_resolve);
}
function fail_callback(param_from_reject) {
console.log('fail(): ', param_from_reject);
}
promise_instance
.then(success_callback)
.catch(fail_callback);
Will become:
new Promise((resolve_callback_provided_by_promise_instance,
reject_callback_provided_by_promise_instance) => {
if (<some_condition>) {
// success
var response='bla';
resolve_callback_provided_by_promise_instance(response);
} else {
// fail
var error=new Error('failed');
reject_callback_provided_by_promise_instance(error);
}})
// "response" -> "param_from_resolve"
.then((param_from_resolve) => { console.log('success() ', param_from_resolve); })
// "error" -> "param_from_reject"
.catch((param_from_reject) => { console.log('fail(): ', param_from_reject); });

About chaining es6 Promises, then() and value consumption

This is tightly coupled to Chaining .then() calls in ES6 promises ...
I tried this with some functions that make up a chain of promises, so basically:
var PromiseGeneratingMethod = function(){
return p = new Promise((resolve, reject) =>{
resolve(1)
});
}
var inBetweenMethod = function(){
return PromiseGeneratingMethod()
.then((resolved) => {
if(resolved){
console.log('resolved in between');
//return resolved
/* this changes output to
resolved in between
resolved at last*/
}else{
console.log('something went terribly wrong in betweeen', resolved);
}
});
}
inBetweenMethod().then((resolved) =>{
if(resolved){
console.log('resolved at last')
}else{
console.log('something went terribly wrong', resolved);
}
})
/* ouput:
resolved in between
something went terribly wrong undefined*/
I don't understand why it is like that. doesn't have a Promise just ONE associated return value? why can I change that value in every then? It seems irrational to me. A Promise Object can only have one return value and I thought every then handler will receive the same parameter after the Promise gets resolved?
This way, having two Methods which call then() on the same Promise, the latter one (in asynchronous environments you never know what that is...) will ALWAYS get an empty result, except if EVERY then returns the desired value
If I got it right, the only good thing is that you can build a then().then().then() chain to make it almost synchronous (by returning arbitrary values in every then()) but you still could achieve the same with nested Promises, right?
Can someone help me understand why es6 Promises work that way and if there are more caveats to using those?
doesn't have a promise just ONE associated return value?
Yes.
why can I change that value in every then?
Because every .then() call does return a new promise.
having two methods which call then() on the same Promise
That's not what you're doing. Your then callbacks are installed on different promises, that's why they get different values.
You could do
function inBetweenMethod() {
var promise = PromiseGeneratingMethod();
promise.then(resolved => { … }); // return value is ignored
return promise;
}
but you should really avoid that. You already noticed that you can get the expected behaviour with
function inBetweenMethod() {
var promise = PromiseGeneratingMethod();
var newPromise = promise.then(value => {
…
return value;
});
return newPromise;
}
where the newPromise is resolved with the value that is returned by the callback - possibly the same value that promise fulfilled with.
you are using .then() handler twice, do the following:
var PromiseGeneratingMethod = function(){
return new Promise((resolve, reject) =>{
if (myCondition) resolve(1)
if (!myCondition) reject("failed")
});
}
var inBetweenMethod = function(){
return PromiseGeneratingMethod()
}
inBetweenMethod().then((resolved) =>{
console.log(resolved)
}).catch(function(err) {
console.log(err)
})

javascript: Making a async loop synchronous [duplicate]

I have an array of promise objects that must be resolved in the same sequence in which they are listed in the array, i.e. we cannot attempt resolving an element till the previous one has been resolved (as method Promise.all([...]) does).
And if one element is rejected, I need the chain to reject at once, without attempting to resolve the following element.
How can I implement this, or is there an existing implementation for such sequence pattern?
function sequence(arr) {
return new Promise(function (resolve, reject) {
// try resolving all elements in 'arr',
// but strictly one after another;
});
}
EDIT
The initial answers suggest we can only sequence results of such array elements, not their execution, because it is predefined in such example.
But then how to generate an array of promises in such a way as to avoid early execution?
Here's a modified example:
function sequence(nextPromise) {
// while nextPromise() creates and returns another promise,
// continue resolving it;
}
I wouldn't want to make it into a separate question, because I believe it is part of the same problem.
SOLUTION
Some answers below and discussions that followed went a bit astray, but the eventual solution that did exactly what I was looking for was implemented within spex library, as method sequence. The method can iterate through a sequence of dynamic length, and create promises as required by the business logic of your application.
Later on I turned it into a shared library for everyone to use.
Here are some simple examples for how you sequence through an array executing each async operation serially (one after the other).
Let's suppose you have an array of items:
var arr = [...];
And, you want to carry out a specific async operation on each item in the array, one at a time serially such that the next operation does not start until the previous one has finished.
And, let's suppose you have a promise returning function for processing one of the items in the array fn(item):
Manual Iteration
function processItem(item) {
// do async operation and process the result
// return a promise
}
Then, you can do something like this:
function processArray(array, fn) {
var index = 0;
function next() {
if (index < array.length) {
fn(array[index++]).then(next);
}
}
return next();
}
processArray(arr, processItem);
Manual Iteration Returning Promise
If you wanted a promise returned from processArray() so you'd know when it was done, you could add this to it:
function processArray(array, fn) {
var index = 0;
function next() {
if (index < array.length) {
return fn(array[index++]).then(function(value) {
// apply some logic to value
// you have three options here:
// 1) Call next() to continue processing the result of the array
// 2) throw err to stop processing and result in a rejected promise being returned
// 3) return value to stop processing and result in a resolved promise being returned
return next();
});
}
} else {
// return whatever you want to return when all processing is done
// this returne value will be the ersolved value of the returned promise.
return "all done";
}
return next();
}
processArray(arr, processItem).then(function(result) {
// all done here
console.log(result);
}, function(err) {
// rejection happened
console.log(err);
});
Note: this will stop the chain on the first rejection and pass that reason back to the processArray returned promise.
Iteration with .reduce()
If you wanted to do more of the work with promises, you could chain all the promises:
function processArray(array, fn) {
return array.reduce(function(p, item) {
return p.then(function() {
return fn(item);
});
}, Promise.resolve());
}
processArray(arr, processItem).then(function(result) {
// all done here
}, function(reason) {
// rejection happened
});
Note: this will stop the chain on the first rejection and pass that reason back to the promise returned from processArray().
For a success scenario, the promise returned from processArray() will be resolved with the last resolved value of your fn callback. If you wanted to accumulate a list of results and resolve with that, you could collect the results in a closure array from fn and continue to return that array each time so the final resolve would be an array of results.
Iteration with .reduce() that Resolves With Array
And, since it now seems apparent that you want the final promise result to be an array of data (in order), here's a revision of the previous solution that produces that:
function processArray(array, fn) {
var results = [];
return array.reduce(function(p, item) {
return p.then(function() {
return fn(item).then(function(data) {
results.push(data);
return results;
});
});
}, Promise.resolve());
}
processArray(arr, processItem).then(function(result) {
// all done here
// array of data here in result
}, function(reason) {
// rejection happened
});
Working demo: http://jsfiddle.net/jfriend00/h3zaw8u8/
And a working demo that shows a rejection: http://jsfiddle.net/jfriend00/p0ffbpoc/
Iteration with .reduce() that Resolves With Array with delay
And, if you want to insert a small delay between operations:
function delay(t, v) {
return new Promise(function(resolve) {
setTimeout(resolve.bind(null, v), t);
});
}
function processArrayWithDelay(array, t, fn) {
var results = [];
return array.reduce(function(p, item) {
return p.then(function() {
return fn(item).then(function(data) {
results.push(data);
return delay(t, results);
});
});
}, Promise.resolve());
}
processArray(arr, 200, processItem).then(function(result) {
// all done here
// array of data here in result
}, function(reason) {
// rejection happened
});
Iteration with Bluebird Promise Library
The Bluebird promise library has a lot of concurrency controlling features built right in. For example, to sequence iteration through an array, you can use Promise.mapSeries().
Promise.mapSeries(arr, function(item) {
// process each individual item here, return a promise
return processItem(item);
}).then(function(results) {
// process final results here
}).catch(function(err) {
// process array here
});
Or to insert a delay between iterations:
Promise.mapSeries(arr, function(item) {
// process each individual item here, return a promise
return processItem(item).delay(100);
}).then(function(results) {
// process final results here
}).catch(function(err) {
// process array here
});
Using ES7 async/await
If you're coding in an environment that supports async/await, you can also just use a regular for loop and then await a promise in the loop and it will cause the for loop to pause until a promise is resolved before proceeding. This will effectively sequence your async operations so the next one doesn't start until the previous one is done.
async function processArray(array, fn) {
let results = [];
for (let i = 0; i < array.length; i++) {
let r = await fn(array[i]);
results.push(r);
}
return results; // will be resolved value of promise
}
// sample usage
processArray(arr, processItem).then(function(result) {
// all done here
// array of data here in result
}, function(reason) {
// rejection happened
});
FYI, I think my processArray() function here is very similar to Promise.map() in the Bluebird promise library which takes an array and a promise producing function and returns a promise that resolves with an array of resolved results.
#vitaly-t - Here some some more detailed comments on your approach. You are welcome to whatever code seems best to you. When I first started using promises, I tended to use promises only for the simplest things they did and write a lot of the logic myself when a more advanced use of promises could do much more of it for me. You use only what you are fully comfortable with and beyond that, you'd rather see your own code that you intimately know. That's probably human nature.
I will suggest that as I understood more and more of what promises can do for me, I now like to write code that uses more of the advanced features of promises and it seems perfectly natural to me and I feel like I'm building on well tested infrastructure that has lots of useful features. I'd only ask that you keep your mind open as you learn more and more to potentially go that direction. It's my opinion that it's a useful and productive direction to migrate as your understanding improves.
Here are some specific points of feedback on your approach:
You create promises in seven places
As a contrast in styles, my code has only two places where I explicitly create a new promise - once in the factory function and once to initialize the .reduce() loop. Everywhere else, I'm just building on the promises already created by chaining to them or returning values within them or just returning them directly. Your code has seven unique places where you're creating a promise. Now, good coding isn't a contest to see how few places you can create a promise, but that might point out the difference in leverage the promises that are already created versus testing conditions and creating new promises.
Throw-safety is a very useful feature
Promises are throw-safe. That means that an exception thrown within a promise handler will automatically reject that promise. If you just want the exception to become a rejection, then this is a very useful feature to take advantage of. In fact, you will find that just throwing yourself is a useful way to reject from within a handler without creating yet another promise.
Lots of Promise.resolve() or Promise.reject() is probably an opportunity for simplification
If you see code with lots of Promise.resolve() or Promise.reject() statements, then there are probably opportunities to leverage the existing promises better rather than creating all these new promises.
Cast to a Promise
If you don't know if something returned a promise, then you can cast it to a promise. The promise library will then do it's own checks whether it is a promise or not and even whether it's the kind of promise that matches the promise library you're using and, if not, wrap it into one. This can save rewriting a lot of this logic yourself.
Contract to Return a Promise
In many cases these days, it's completely viable to have a contract for a function that may do something asynchronous to return a promise. If the function just wants to do something synchronous, then it can just return a resolved promise. You seem to feel like this is onerous, but it's definitely the way the wind is blowing and I already write lots of code that requires that and it feels very natural once you get familiar with promises. It abstracts away whether the operation is sync or async and the caller doesn't have to know or do anything special either way. This is a nice use of promises.
The factory function can be written to create one promise only
The factory function can be written to create one promise only and then resolve or reject it. This style also makes it throw safe so any exception occuring in the factory function automatically becomes a reject. It also makes the contract to always return a promise automatic.
While I realize this factory function is a placeholder function (it doesn't even do anything async), hopefully you can see the style to consider it:
function factory(idx) {
// create the promise this way gives you automatic throw-safety
return new Promise(function(resolve, reject) {
switch (idx) {
case 0:
resolve("one");
break;
case 1:
resolve("two");
break;
case 2:
resolve("three");
break;
default:
resolve(null);
break;
}
});
}
If any of these operations were async, then they could just return their own promises which would automatically chain to the one central promise like this:
function factory(idx) {
// create the promise this way gives you automatic throw-safety
return new Promise(function(resolve, reject) {
switch (idx) {
case 0:
resolve($.ajax(...));
case 1:
resole($.ajax(...));
case 2:
resolve("two");
break;
default:
resolve(null);
break;
}
});
}
Using a reject handler to just return promise.reject(reason) is not needed
When you have this body of code:
return obj.then(function (data) {
result.push(data);
return loop(++idx, result);
}, function (reason) {
return promise.reject(reason);
});
The reject handler is not adding any value. You can instead just do this:
return obj.then(function (data) {
result.push(data);
return loop(++idx, result);
});
You are already returning the result of obj.then(). If either obj rejects or if anything chained to obj or returned from then .then() handler rejects, then obj will reject. So you don't need to create a new promise with the reject. The simpler code without the reject handler does the same thing with less code.
Here's a version in the general architecture of your code that tries to incorporate most of these ideas:
function factory(idx) {
// create the promise this way gives you automatic throw-safety
return new Promise(function(resolve, reject) {
switch (idx) {
case 0:
resolve("zero");
break;
case 1:
resolve("one");
break;
case 2:
resolve("two");
break;
default:
// stop further processing
resolve(null);
break;
}
});
}
// Sequentially resolves dynamic promises returned by a factory;
function sequence(factory) {
function loop(idx, result) {
return Promise.resolve(factory(idx)).then(function(val) {
// if resolved value is not null, then store result and keep going
if (val !== null) {
result.push(val);
// return promise from next call to loop() which will automatically chain
return loop(++idx, result);
} else {
// if we got null, then we're done so return results
return result;
}
});
}
return loop(0, []);
}
sequence(factory).then(function(results) {
log("results: ", results);
}, function(reason) {
log("rejected: ", reason);
});
Working demo: http://jsfiddle.net/jfriend00/h3zaw8u8/
Some comments about this implementation:
Promise.resolve(factory(idx)) essentially casts the result of factory(idx) to a promise. If it was just a value, then it becomes a resolved promise with that return value as the resolve value. If it was already a promise, then it just chains to that promise. So, it replaces all your type checking code on the return value of the factory() function.
The factory function signals that it is done by returning either null or a promise whose resolved value ends up being null. The above cast maps those two conditions to the same resulting code.
The factory function catches exceptions automatically and turns them into rejects which are then handled automatically by the sequence() function. This is one significant advantage of letting promises do a lot of your error handling if you just want to abort processing and feed the error back on the first exception or rejection.
The factory function in this implementation can return either a promise or a static value (for a synchronous operation) and it will work just fine (per your design request).
I've tested it with a thrown exception in the promise callback in the factory function and it does indeed just reject and propagate that exception back to reject the sequence promise with the exception as the reason.
This uses a similar method as you (on purpose, trying to stay with your general architecture) for chaining multiple calls to loop().
Promises represent values of operations and not the operations themselves. The operations are already started so you can't make them wait for one another.
Instead, you can synchronize functions that return promises invoking them in order (through a loop with promise chaining for instance), or using the .each method in bluebird.
You can't simply run X async operations and then want them to be resolved in an order.
The correct way to do something like this is to run the new async operation only after the one before was resolved:
doSomethingAsync().then(function(){
doSomethingAsync2().then(function(){
doSomethingAsync3();
.......
});
});
Edit Seems like you want to wait for all promises and then invoke their callbacks in a specific order. Something like this:
var callbackArr = [];
var promiseArr = [];
promiseArr.push(doSomethingAsync());
callbackArr.push(doSomethingAsyncCallback);
promiseArr.push(doSomethingAsync1());
callbackArr.push(doSomethingAsync1Callback);
.........
promiseArr.push(doSomethingAsyncN());
callbackArr.push(doSomethingAsyncNCallback);
and then:
$.when(promiseArr).done(function(promise){
while(callbackArr.length > 0)
{
callbackArr.pop()(promise);
}
});
The problems that can occur with this is when one or more promises fail.
Although quite dense, here's another solution that will iterate a promise-returning function over an array of values and resolve with an array of results:
function processArray(arr, fn) {
return arr.reduce(
(p, v) => p.then((a) => fn(v).then(r => a.concat([r]))),
Promise.resolve([])
);
}
Usage:
const numbers = [0, 4, 20, 100];
const multiplyBy3 = (x) => new Promise(res => res(x * 3));
// Prints [ 0, 12, 60, 300 ]
processArray(numbers, multiplyBy3).then(console.log);
Note that, because we're reducing from one promise to the next, each item is processed in series.
It's functionally equivalent to the "Iteration with .reduce() that Resolves With Array" solution from #jfriend00 but a bit neater.
I suppose two approaches for handling this question:
Create multiple promises and use the allWithAsync function as follow:
let allPromiseAsync = (...PromisesList) => {
return new Promise(async resolve => {
let output = []
for (let promise of PromisesList) {
output.push(await promise.then(async resolvedData => await resolvedData))
if (output.length === PromisesList.length) resolve(output)
}
}) }
const prm1= Promise.resolve('first');
const prm2= new Promise((resolve, reject) => setTimeout(resolve, 2000, 'second'));
const prm3= Promise.resolve('third');
allPromiseAsync(prm1, prm2, prm3)
.then(resolvedData => {
console.log(resolvedData) // ['first', 'second', 'third']
});
Use the Promise.all function instead:
(async () => {
const promise1 = new Promise(resolve => {
setTimeout(() => { console.log('first');console.log(new Date());resolve() }, 1000)
})
const promise2 = new Promise(resolve => {
setTimeout(() => {console.log('second');console.log(new Date()); resolve() }, 3000)
})
const promise3 = new Promise(resolve => {
setTimeout(() => { console.log('third');console.log(new Date()); resolve() }, 7000)
})
const promises = [promise1, promise2, promise3]
await Promise.all(promises)
console.log('This line is shown after 7000ms')
})()
In my opinion, you should be using a for loop(yes the only time I would recommend a for loop). The reason is that when you are using a for loop it allows you to await on each of the iterations of your loop where using reduce, map or forEach with run all your promise iterations concurrently. Which by the sounds of it is not what you want, you want each promise to wait until the previous promise has resolved. So to do this you would do something like the following.
const ids = [0, 1, 2]
const accounts = ids.map(id => getId(id))
const accountData = async() => {
for await (const account of accounts) {
// account will equal the current iteration of the loop
// and each promise are now waiting on the previous promise to resolve!
}
}
// then invoke your function where ever needed
accountData()
And obviously, if you wanted to get really extreme you could do something like this:
const accountData = async(accounts) => {
for await (const account of accounts) {
// do something
}
}
accountData([0, 1, 2].map(id => getId(id)))
This is so much more readable than any of the other examples, it is much less code, reduced the number of lines needed for this functionality, follows a more functional programming way of doing things and is using ES7 to its full potential!!!!
Also depending on your set up or when you are reading this you may need to add the plugin-proposal-async-generator-functions polyfill or you may see the following error
#babel/plugin-proposal-async-generator-functions (https://git.io/vb4yp) to the 'plugins' section of your Babel config to enable transformation.

How to synchronize a sequence of promises?

I have an array of promise objects that must be resolved in the same sequence in which they are listed in the array, i.e. we cannot attempt resolving an element till the previous one has been resolved (as method Promise.all([...]) does).
And if one element is rejected, I need the chain to reject at once, without attempting to resolve the following element.
How can I implement this, or is there an existing implementation for such sequence pattern?
function sequence(arr) {
return new Promise(function (resolve, reject) {
// try resolving all elements in 'arr',
// but strictly one after another;
});
}
EDIT
The initial answers suggest we can only sequence results of such array elements, not their execution, because it is predefined in such example.
But then how to generate an array of promises in such a way as to avoid early execution?
Here's a modified example:
function sequence(nextPromise) {
// while nextPromise() creates and returns another promise,
// continue resolving it;
}
I wouldn't want to make it into a separate question, because I believe it is part of the same problem.
SOLUTION
Some answers below and discussions that followed went a bit astray, but the eventual solution that did exactly what I was looking for was implemented within spex library, as method sequence. The method can iterate through a sequence of dynamic length, and create promises as required by the business logic of your application.
Later on I turned it into a shared library for everyone to use.
Here are some simple examples for how you sequence through an array executing each async operation serially (one after the other).
Let's suppose you have an array of items:
var arr = [...];
And, you want to carry out a specific async operation on each item in the array, one at a time serially such that the next operation does not start until the previous one has finished.
And, let's suppose you have a promise returning function for processing one of the items in the array fn(item):
Manual Iteration
function processItem(item) {
// do async operation and process the result
// return a promise
}
Then, you can do something like this:
function processArray(array, fn) {
var index = 0;
function next() {
if (index < array.length) {
fn(array[index++]).then(next);
}
}
return next();
}
processArray(arr, processItem);
Manual Iteration Returning Promise
If you wanted a promise returned from processArray() so you'd know when it was done, you could add this to it:
function processArray(array, fn) {
var index = 0;
function next() {
if (index < array.length) {
return fn(array[index++]).then(function(value) {
// apply some logic to value
// you have three options here:
// 1) Call next() to continue processing the result of the array
// 2) throw err to stop processing and result in a rejected promise being returned
// 3) return value to stop processing and result in a resolved promise being returned
return next();
});
}
} else {
// return whatever you want to return when all processing is done
// this returne value will be the ersolved value of the returned promise.
return "all done";
}
return next();
}
processArray(arr, processItem).then(function(result) {
// all done here
console.log(result);
}, function(err) {
// rejection happened
console.log(err);
});
Note: this will stop the chain on the first rejection and pass that reason back to the processArray returned promise.
Iteration with .reduce()
If you wanted to do more of the work with promises, you could chain all the promises:
function processArray(array, fn) {
return array.reduce(function(p, item) {
return p.then(function() {
return fn(item);
});
}, Promise.resolve());
}
processArray(arr, processItem).then(function(result) {
// all done here
}, function(reason) {
// rejection happened
});
Note: this will stop the chain on the first rejection and pass that reason back to the promise returned from processArray().
For a success scenario, the promise returned from processArray() will be resolved with the last resolved value of your fn callback. If you wanted to accumulate a list of results and resolve with that, you could collect the results in a closure array from fn and continue to return that array each time so the final resolve would be an array of results.
Iteration with .reduce() that Resolves With Array
And, since it now seems apparent that you want the final promise result to be an array of data (in order), here's a revision of the previous solution that produces that:
function processArray(array, fn) {
var results = [];
return array.reduce(function(p, item) {
return p.then(function() {
return fn(item).then(function(data) {
results.push(data);
return results;
});
});
}, Promise.resolve());
}
processArray(arr, processItem).then(function(result) {
// all done here
// array of data here in result
}, function(reason) {
// rejection happened
});
Working demo: http://jsfiddle.net/jfriend00/h3zaw8u8/
And a working demo that shows a rejection: http://jsfiddle.net/jfriend00/p0ffbpoc/
Iteration with .reduce() that Resolves With Array with delay
And, if you want to insert a small delay between operations:
function delay(t, v) {
return new Promise(function(resolve) {
setTimeout(resolve.bind(null, v), t);
});
}
function processArrayWithDelay(array, t, fn) {
var results = [];
return array.reduce(function(p, item) {
return p.then(function() {
return fn(item).then(function(data) {
results.push(data);
return delay(t, results);
});
});
}, Promise.resolve());
}
processArray(arr, 200, processItem).then(function(result) {
// all done here
// array of data here in result
}, function(reason) {
// rejection happened
});
Iteration with Bluebird Promise Library
The Bluebird promise library has a lot of concurrency controlling features built right in. For example, to sequence iteration through an array, you can use Promise.mapSeries().
Promise.mapSeries(arr, function(item) {
// process each individual item here, return a promise
return processItem(item);
}).then(function(results) {
// process final results here
}).catch(function(err) {
// process array here
});
Or to insert a delay between iterations:
Promise.mapSeries(arr, function(item) {
// process each individual item here, return a promise
return processItem(item).delay(100);
}).then(function(results) {
// process final results here
}).catch(function(err) {
// process array here
});
Using ES7 async/await
If you're coding in an environment that supports async/await, you can also just use a regular for loop and then await a promise in the loop and it will cause the for loop to pause until a promise is resolved before proceeding. This will effectively sequence your async operations so the next one doesn't start until the previous one is done.
async function processArray(array, fn) {
let results = [];
for (let i = 0; i < array.length; i++) {
let r = await fn(array[i]);
results.push(r);
}
return results; // will be resolved value of promise
}
// sample usage
processArray(arr, processItem).then(function(result) {
// all done here
// array of data here in result
}, function(reason) {
// rejection happened
});
FYI, I think my processArray() function here is very similar to Promise.map() in the Bluebird promise library which takes an array and a promise producing function and returns a promise that resolves with an array of resolved results.
#vitaly-t - Here some some more detailed comments on your approach. You are welcome to whatever code seems best to you. When I first started using promises, I tended to use promises only for the simplest things they did and write a lot of the logic myself when a more advanced use of promises could do much more of it for me. You use only what you are fully comfortable with and beyond that, you'd rather see your own code that you intimately know. That's probably human nature.
I will suggest that as I understood more and more of what promises can do for me, I now like to write code that uses more of the advanced features of promises and it seems perfectly natural to me and I feel like I'm building on well tested infrastructure that has lots of useful features. I'd only ask that you keep your mind open as you learn more and more to potentially go that direction. It's my opinion that it's a useful and productive direction to migrate as your understanding improves.
Here are some specific points of feedback on your approach:
You create promises in seven places
As a contrast in styles, my code has only two places where I explicitly create a new promise - once in the factory function and once to initialize the .reduce() loop. Everywhere else, I'm just building on the promises already created by chaining to them or returning values within them or just returning them directly. Your code has seven unique places where you're creating a promise. Now, good coding isn't a contest to see how few places you can create a promise, but that might point out the difference in leverage the promises that are already created versus testing conditions and creating new promises.
Throw-safety is a very useful feature
Promises are throw-safe. That means that an exception thrown within a promise handler will automatically reject that promise. If you just want the exception to become a rejection, then this is a very useful feature to take advantage of. In fact, you will find that just throwing yourself is a useful way to reject from within a handler without creating yet another promise.
Lots of Promise.resolve() or Promise.reject() is probably an opportunity for simplification
If you see code with lots of Promise.resolve() or Promise.reject() statements, then there are probably opportunities to leverage the existing promises better rather than creating all these new promises.
Cast to a Promise
If you don't know if something returned a promise, then you can cast it to a promise. The promise library will then do it's own checks whether it is a promise or not and even whether it's the kind of promise that matches the promise library you're using and, if not, wrap it into one. This can save rewriting a lot of this logic yourself.
Contract to Return a Promise
In many cases these days, it's completely viable to have a contract for a function that may do something asynchronous to return a promise. If the function just wants to do something synchronous, then it can just return a resolved promise. You seem to feel like this is onerous, but it's definitely the way the wind is blowing and I already write lots of code that requires that and it feels very natural once you get familiar with promises. It abstracts away whether the operation is sync or async and the caller doesn't have to know or do anything special either way. This is a nice use of promises.
The factory function can be written to create one promise only
The factory function can be written to create one promise only and then resolve or reject it. This style also makes it throw safe so any exception occuring in the factory function automatically becomes a reject. It also makes the contract to always return a promise automatic.
While I realize this factory function is a placeholder function (it doesn't even do anything async), hopefully you can see the style to consider it:
function factory(idx) {
// create the promise this way gives you automatic throw-safety
return new Promise(function(resolve, reject) {
switch (idx) {
case 0:
resolve("one");
break;
case 1:
resolve("two");
break;
case 2:
resolve("three");
break;
default:
resolve(null);
break;
}
});
}
If any of these operations were async, then they could just return their own promises which would automatically chain to the one central promise like this:
function factory(idx) {
// create the promise this way gives you automatic throw-safety
return new Promise(function(resolve, reject) {
switch (idx) {
case 0:
resolve($.ajax(...));
case 1:
resole($.ajax(...));
case 2:
resolve("two");
break;
default:
resolve(null);
break;
}
});
}
Using a reject handler to just return promise.reject(reason) is not needed
When you have this body of code:
return obj.then(function (data) {
result.push(data);
return loop(++idx, result);
}, function (reason) {
return promise.reject(reason);
});
The reject handler is not adding any value. You can instead just do this:
return obj.then(function (data) {
result.push(data);
return loop(++idx, result);
});
You are already returning the result of obj.then(). If either obj rejects or if anything chained to obj or returned from then .then() handler rejects, then obj will reject. So you don't need to create a new promise with the reject. The simpler code without the reject handler does the same thing with less code.
Here's a version in the general architecture of your code that tries to incorporate most of these ideas:
function factory(idx) {
// create the promise this way gives you automatic throw-safety
return new Promise(function(resolve, reject) {
switch (idx) {
case 0:
resolve("zero");
break;
case 1:
resolve("one");
break;
case 2:
resolve("two");
break;
default:
// stop further processing
resolve(null);
break;
}
});
}
// Sequentially resolves dynamic promises returned by a factory;
function sequence(factory) {
function loop(idx, result) {
return Promise.resolve(factory(idx)).then(function(val) {
// if resolved value is not null, then store result and keep going
if (val !== null) {
result.push(val);
// return promise from next call to loop() which will automatically chain
return loop(++idx, result);
} else {
// if we got null, then we're done so return results
return result;
}
});
}
return loop(0, []);
}
sequence(factory).then(function(results) {
log("results: ", results);
}, function(reason) {
log("rejected: ", reason);
});
Working demo: http://jsfiddle.net/jfriend00/h3zaw8u8/
Some comments about this implementation:
Promise.resolve(factory(idx)) essentially casts the result of factory(idx) to a promise. If it was just a value, then it becomes a resolved promise with that return value as the resolve value. If it was already a promise, then it just chains to that promise. So, it replaces all your type checking code on the return value of the factory() function.
The factory function signals that it is done by returning either null or a promise whose resolved value ends up being null. The above cast maps those two conditions to the same resulting code.
The factory function catches exceptions automatically and turns them into rejects which are then handled automatically by the sequence() function. This is one significant advantage of letting promises do a lot of your error handling if you just want to abort processing and feed the error back on the first exception or rejection.
The factory function in this implementation can return either a promise or a static value (for a synchronous operation) and it will work just fine (per your design request).
I've tested it with a thrown exception in the promise callback in the factory function and it does indeed just reject and propagate that exception back to reject the sequence promise with the exception as the reason.
This uses a similar method as you (on purpose, trying to stay with your general architecture) for chaining multiple calls to loop().
Promises represent values of operations and not the operations themselves. The operations are already started so you can't make them wait for one another.
Instead, you can synchronize functions that return promises invoking them in order (through a loop with promise chaining for instance), or using the .each method in bluebird.
You can't simply run X async operations and then want them to be resolved in an order.
The correct way to do something like this is to run the new async operation only after the one before was resolved:
doSomethingAsync().then(function(){
doSomethingAsync2().then(function(){
doSomethingAsync3();
.......
});
});
Edit Seems like you want to wait for all promises and then invoke their callbacks in a specific order. Something like this:
var callbackArr = [];
var promiseArr = [];
promiseArr.push(doSomethingAsync());
callbackArr.push(doSomethingAsyncCallback);
promiseArr.push(doSomethingAsync1());
callbackArr.push(doSomethingAsync1Callback);
.........
promiseArr.push(doSomethingAsyncN());
callbackArr.push(doSomethingAsyncNCallback);
and then:
$.when(promiseArr).done(function(promise){
while(callbackArr.length > 0)
{
callbackArr.pop()(promise);
}
});
The problems that can occur with this is when one or more promises fail.
Although quite dense, here's another solution that will iterate a promise-returning function over an array of values and resolve with an array of results:
function processArray(arr, fn) {
return arr.reduce(
(p, v) => p.then((a) => fn(v).then(r => a.concat([r]))),
Promise.resolve([])
);
}
Usage:
const numbers = [0, 4, 20, 100];
const multiplyBy3 = (x) => new Promise(res => res(x * 3));
// Prints [ 0, 12, 60, 300 ]
processArray(numbers, multiplyBy3).then(console.log);
Note that, because we're reducing from one promise to the next, each item is processed in series.
It's functionally equivalent to the "Iteration with .reduce() that Resolves With Array" solution from #jfriend00 but a bit neater.
I suppose two approaches for handling this question:
Create multiple promises and use the allWithAsync function as follow:
let allPromiseAsync = (...PromisesList) => {
return new Promise(async resolve => {
let output = []
for (let promise of PromisesList) {
output.push(await promise.then(async resolvedData => await resolvedData))
if (output.length === PromisesList.length) resolve(output)
}
}) }
const prm1= Promise.resolve('first');
const prm2= new Promise((resolve, reject) => setTimeout(resolve, 2000, 'second'));
const prm3= Promise.resolve('third');
allPromiseAsync(prm1, prm2, prm3)
.then(resolvedData => {
console.log(resolvedData) // ['first', 'second', 'third']
});
Use the Promise.all function instead:
(async () => {
const promise1 = new Promise(resolve => {
setTimeout(() => { console.log('first');console.log(new Date());resolve() }, 1000)
})
const promise2 = new Promise(resolve => {
setTimeout(() => {console.log('second');console.log(new Date()); resolve() }, 3000)
})
const promise3 = new Promise(resolve => {
setTimeout(() => { console.log('third');console.log(new Date()); resolve() }, 7000)
})
const promises = [promise1, promise2, promise3]
await Promise.all(promises)
console.log('This line is shown after 7000ms')
})()
In my opinion, you should be using a for loop(yes the only time I would recommend a for loop). The reason is that when you are using a for loop it allows you to await on each of the iterations of your loop where using reduce, map or forEach with run all your promise iterations concurrently. Which by the sounds of it is not what you want, you want each promise to wait until the previous promise has resolved. So to do this you would do something like the following.
const ids = [0, 1, 2]
const accounts = ids.map(id => getId(id))
const accountData = async() => {
for await (const account of accounts) {
// account will equal the current iteration of the loop
// and each promise are now waiting on the previous promise to resolve!
}
}
// then invoke your function where ever needed
accountData()
And obviously, if you wanted to get really extreme you could do something like this:
const accountData = async(accounts) => {
for await (const account of accounts) {
// do something
}
}
accountData([0, 1, 2].map(id => getId(id)))
This is so much more readable than any of the other examples, it is much less code, reduced the number of lines needed for this functionality, follows a more functional programming way of doing things and is using ES7 to its full potential!!!!
Also depending on your set up or when you are reading this you may need to add the plugin-proposal-async-generator-functions polyfill or you may see the following error
#babel/plugin-proposal-async-generator-functions (https://git.io/vb4yp) to the 'plugins' section of your Babel config to enable transformation.

Dojo promise all -- but that waits for all promises to return

I am using dojo promises, with deferred. I have a promise/all that catches all of the promises and only executes when they are all successful or when any one of them returns an error. Is there a way to have a list of promises that only returns when all are executed(regardless if they were successful or error)? I'd like to have a list of the ones that failed, instead of "one of these failed".
I guess I could just resolve all of the deferreds, error or success, but that kinda defeats the purpose...
There are two alternatives for this:
Settle
Dojo promises offer no tools for managing this case explicitly ala' bluebird's Promise.settle or when's when.settle. So we pretty much have to create it ourselves:
function settle(promises){ // assuming "dojo/promise/all" and "dojo/Deferred"
var d = new Deferred();
var countdownLatch = promises.length;
var results = [];
promises.forEach(function(p, i){
p.then(function(v){
results[i] = {state: "fulfilled", value: v};
countdownLatch--;
if(countdownLatch === 0) d.resolve(results);
}, function(err){
results[i] = {state: "rejected", err: err };
countdownLatch--;
if(countdownLatch === 0) d.resolve(results);
});
});
return d; // dojo mixes deferred and promises because it's an older API
}
This would let you do:
settle(myPromisesArray).then(function(results){
results.forEach(function(res){
console.log(res.state); // you can `if` on it to check a particular promise
});
});
Reflect
A more modern approach is to create a reflect method that takes a promise and returns a promise that always fulfills with an object containing the previous promise's state. This is a direction Bluebird is exploring and will possibly be included in V3.
function reflect(promise){
return promise.then(function(v){ return {state: "fulfilled", value: v }; },
function(e){ return {state: "rejected" , error: e }; });
}
Which would let you do different aggregations, this makes settle from above a private case with:
function settle(promises){
return all(promises.map(reflect));
}
As you've found, dojo/promise/all is fulfilled as soon as one of the constituent promises is cancelled.
You want dojo/DeferredList - this can be configured to do what you want, and you can extract the promise object from it.

Categories