I need to implement a version of Promise.all
that would take an array of promises and return the result as it usually does, plus also settles all promises, much like Promise.settle
does it within the Bluebird
library, except I cannot use Bluebird
, and have to rely just on the standard promise protocol.
Would that be terribly plicated to implement? Or is it too much to ask here for an idea of how to implement it? I really hope not, so I'm asking, if anyone perhaps implemented it before, to share the idea of how to do it right.
The premise for this is to be able to use it within a database transaction that needs to do mit
/rollback
once the call has finished, and it cannot have loose promises still trying to resolve outside the transaction call.
EDIT: The link provided to another question is very useful, but it is not a plete answer to the question that was asked. A generic settle
is a great example that helped a lot, but it needed to be simplified and wrapped into all
logic to fit the transactions scenario described earlier.
I need to implement a version of Promise.all
that would take an array of promises and return the result as it usually does, plus also settles all promises, much like Promise.settle
does it within the Bluebird
library, except I cannot use Bluebird
, and have to rely just on the standard promise protocol.
Would that be terribly plicated to implement? Or is it too much to ask here for an idea of how to implement it? I really hope not, so I'm asking, if anyone perhaps implemented it before, to share the idea of how to do it right.
The premise for this is to be able to use it within a database transaction that needs to do mit
/rollback
once the call has finished, and it cannot have loose promises still trying to resolve outside the transaction call.
EDIT: The link provided to another question is very useful, but it is not a plete answer to the question that was asked. A generic settle
is a great example that helped a lot, but it needed to be simplified and wrapped into all
logic to fit the transactions scenario described earlier.
-
3
Code provided for exactly what you're asking for here (in the second code example named
promiseSettle()
): Wait for multiple promises to be rejected. Marked this question as a dup of that one. – jfriend00 Commented Sep 8, 2015 at 22:52 - It was a very useful reference, although offering only half the answer. – vitaly-t Commented Sep 9, 2015 at 0:27
- What half is missing. It runs all promises and tells you when they are all done. – jfriend00 Commented Sep 9, 2015 at 0:31
- It creates a needless array of objects with fulfilled statuses, and it doesn't implement the merging logic like the one I wrote based on the example. – vitaly-t Commented Sep 9, 2015 at 0:32
-
A simplification, more like, because some things in the generic implementation are not needed when it is done strictly in the context of
all
as the containing operation. – vitaly-t Commented Sep 9, 2015 at 0:37
3 Answers
Reset to default 6I think the solution by jfriend is overly plex because it builds on top of settle
, it runs a semaphore and does a lot of weird stuff instead of using the built in primitives like .all
.
Instead, if we build on Bluebird's newer reflect
primitive (implementing it in native promises) we can get a much cleaner API and implementation:
function reflect(promise){
return promise.then(x => ({state: "fulfilled", value: x}), // arrows, assume nodejs
e => ({state: "rejected" , value: e}));
}
On top of reflect, we can build the other primitives easily:
function settle(promises){
return Promise.all(promises.map(reflect)); // much cleaner
}
If we want to wait and then resolve/reject based on values it's simply:
function allWait(promises){
return settle(promises).then(results => {
var firstFailed = results.find(r => r.state === "rejected");
if(firstFailed) throw firstFailed.value;
return results;
});
}
Building on the generic promiseSettle()
function from the other question, you could do this and have both a generic settle()
type function and your much more specific version as a wrapper around it. This would give you the generic ability to do lots of .settle()
types of behavior and have your own specific flavor and also build other specific flavors as needed:
So, here's the generic promiseSettle()
that returns you the state of all the promises and resolves only when all the passed-in promises are done:
function promiseSettle(promises) {
return new Promise(function(resolve) {
var remaining = promises.length;
// place to store results in original order
var results = new Array(remaining);
function checkDone() {
if (--remaining === 0) {
resolve(results);
}
}
promises.forEach(function(item, index) {
// check if the array entry is actually a thenable
if (typeof item.then === "function") {
item.then(function(value) {
// success
results[index] = {state: "fulfilled", value: value};
checkDone();
}, function(err) {
// reject error
results[index] = {state: "rejected", value: err};
checkDone();
});
} else {
// not a thenable, just return the item itself
results[index] = {state: "fulfilled", value: item}
--remaining;
}
});
// special case for zero promises passed
if (remaining === 0) {
resolve(results);
}
});
}
And, here's a wrapper on it that gives you your specific behavior:
// Either fulfills with an array of results or
// rejects with the first error, but it does not do either
// until all promises have pleted which makes it different than
// promise.all()
function promiseSettleAll(promises) {
return promiseSettle(promises).then(function(results) {
for (var i = 0; i < results.length; i++) {
if (results[i].state !== "fulfilled") {
// reject with the first error found
throw results[i].value;
}
}
// all were successful, return just array of values
return results.map(function(item) {return item.value;});
});
}
In the end of all the research, writing, testing and optimizations, it was turned into a library (spex) that focuses on this type of things.
Specifically, method batch is the one that implements the fusion of the logic described.
I am not republishing its source code here, because it now does a lot more than what was originally sought within the question.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745268549a4619605.html
评论列表(0条)