Javascript 处理 Promise.all 中的错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30362733/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Handling errors in Promise.all
提问by Jon
I have an array of Promises that I'm resolving with Promise.all(arrayOfPromises);
我有一系列要解决的 Promise Promise.all(arrayOfPromises);
I go on to continue the promise chain. Looks something like this
我继续继续承诺链。看起来像这样
existingPromiseChain = existingPromiseChain.then(function() {
var arrayOfPromises = state.routes.map(function(route){
return route.handler.promiseHandler();
});
return Promise.all(arrayOfPromises)
});
existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {
// do stuff with my array of resolved promises, eventually ending with a res.send();
});
I want to add a catch statement to handle an individual promise in case it errors, but when I try, Promise.allreturns the first error it finds (disregards the rest), and then I can't get the data from the rest of the promises in the array (that didn't error).
我想添加一个 catch 语句来处理单个承诺,以防它出错,但是当我尝试时,Promise.all返回它找到的第一个错误(忽略其余的),然后我无法从其余的承诺中获取数据数组(没有错误)。
I've tried doing something like ..
我试过做类似的事情..
existingPromiseChain = existingPromiseChain.then(function() {
var arrayOfPromises = state.routes.map(function(route){
return route.handler.promiseHandler()
.then(function(data) {
return data;
})
.catch(function(err) {
return err
});
});
return Promise.all(arrayOfPromises)
});
existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {
// do stuff with my array of resolved promises, eventually ending with a res.send();
});
But that doesn't resolve.
但这并不能解决。
Thanks!
谢谢!
--
——
Edit:
编辑:
What the answers below said were completely true, the code was breaking due to other reasons. In case anyone is interested, this is the solution I ended up with ...
下面的答案完全正确,由于其他原因,代码被破坏了。如果有人感兴趣,这是我最终得到的解决方案......
Node Express Server Chain
Node Express 服务器链
serverSidePromiseChain
.then(function(AppRouter) {
var arrayOfPromises = state.routes.map(function(route) {
return route.async();
});
Promise.all(arrayOfPromises)
.catch(function(err) {
// log that I have an error, return the entire array;
console.log('A promise failed to resolve', err);
return arrayOfPromises;
})
.then(function(arrayOfPromises) {
// full array of resolved promises;
})
};
API Call (route.async call)
API 调用(route.async 调用)
return async()
.then(function(result) {
// dispatch a success
return result;
})
.catch(function(err) {
// dispatch a failure and throw error
throw err;
});
Putting the .catchfor Promise.allbefore the .thenseems to have served the purpose of catching any errors from the original promises, but then returning the entire array to the next .then
将.catchfor放在 thePromise.all之前.then似乎是为了从原始承诺中捕获任何错误,但随后将整个数组返回到下一个.then
Thanks!
谢谢!
采纳答案by jib
Promise.allis all or nothing. It resolves once all promises in the array resolve, or reject as soon as oneof them rejects. In other words, it either resolves with an array of all resolved values, or rejects with a single error.
Promise.all全有或全无。一旦数组中的所有承诺解决,它就会解决,或者在其中一个拒绝后立即拒绝。换句话说,它要么使用所有已解析值的数组进行解析,要么以单个错误拒绝。
Some libraries have something called Promise.when, which I understand would instead wait for allpromises in the array to either resolve or reject, but I'm not familiar with it, and it's not in ES6.
一些库有一个叫做 的东西Promise.when,我理解它会等待数组中的所有承诺解决或拒绝,但我不熟悉它,它不在 ES6 中。
Your code
你的代码
I agree with others here that your fix should work. It should resolve with an array that may contain a mix of successful values and errors objects. It's unusual to pass error objects in the success-path but assuming your code is expecting them, I see no problem with it.
我同意这里的其他人的意见,您的修复应该有效。它应该使用一个可能包含成功值和错误对象混合的数组来解析。在成功路径中传递错误对象是不寻常的,但假设您的代码期待它们,我认为它没有问题。
The only reason I can think of why it would "not resolve" is that it's failing in code you're not showing us and the reason you're not seeing any error message about this is because this promise chain is not terminated with a final catch (as far as what you're showing us anyway).
我能想到为什么它“无法解决”的唯一原因是它在您没有向我们展示的代码中失败,并且您没有看到任何关于此的错误消息的原因是因为此承诺链没有以最终抓住(就您向我们展示的内容而言)。
I've taken the liberty of factoring out the "existing chain" from your example and terminating the chain with a catch. This may not be right for you, but for people reading this, it's important to always either return or terminate chains, or potential errors, even coding errors, will get hidden (which is what I suspect happened here):
我冒昧地从您的示例中分解出“现有链”并用捕获终止链。这可能不适合您,但对于阅读本文的人来说,始终返回或终止链很重要,否则潜在的错误,甚至编码错误,将被隐藏(我怀疑这里发生了这种情况):
Promise.all(state.routes.map(function(route) {
return route.handler.promiseHandler().catch(function(err) {
return err;
});
}))
.then(function(arrayOfValuesOrErrors) {
// handling of my array containing values and/or errors.
})
.catch(function(err) {
console.log(err.message); // some coding error in handling happened
});
回答by Solominh
NEW ANSWER
新答案
const results = await Promise.all(promises.map(p => p.catch(e => e)));
const validResults = results.filter(result => !(result instanceof Error));
FUTURE Promise API
未来承诺API
- Chrome 76: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
- You can download https://www.npmjs.com/package/promise.allsettledto get it now. In certain browsers allSettled comes preinstalled with the browser itself. It's worth downloading the package for peace of mind because eg. TypeScript doesn't have default definitions for allSettled.
- Chrome 76:https: //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
- 您可以立即下载https://www.npmjs.com/package/promise.allsettled获取。在某些浏览器中,allSettled 预装了浏览器本身。为了安心,值得下载该软件包,因为例如。TypeScript 没有 allSettled 的默认定义。
回答by Benny Neugebauer
To continue the Promise.allloop (even when a Promise rejects) I wrote a utility function which is called executeAllPromises. This utility function returns an object with resultsand errors.
为了继续Promise.all循环(即使 Promise 拒绝),我编写了一个名为executeAllPromises. 此实用程序函数返回一个带有results和的对象errors。
The idea is that all Promises you pass to executeAllPromiseswill be wrapped into a new Promise which will always resolve. The new Promise resolves with an array which has 2 spots. The first spot holds the resolving value (if any) and the second spot keeps the error (if the wrapped Promise rejects).
这个想法是,您传递给的所有executeAllPromisesPromise 都将被包装到一个新的 Promise 中,该 Promise 将始终解析。新的 Promise 用一个有 2 个点的数组解析。第一个位置保存解析值(如果有),第二个位置保存错误(如果包装的 Promise 拒绝)。
As a final step the executeAllPromisesaccumulates all values of the wrapped promises and returns the final object with an array for resultsand an array for errors.
作为最后一步,它会executeAllPromises累积包装的 Promise 的所有值,并返回带有数组 forresults和数组 for的最终对象errors。
Here is the code:
这是代码:
function executeAllPromises(promises) {
// Wrap all Promises in a Promise that will always "resolve"
var resolvingPromises = promises.map(function(promise) {
return new Promise(function(resolve) {
var payload = new Array(2);
promise.then(function(result) {
payload[0] = result;
})
.catch(function(error) {
payload[1] = error;
})
.then(function() {
/*
* The wrapped Promise returns an array:
* The first position in the array holds the result (if any)
* The second position in the array holds the error (if any)
*/
resolve(payload);
});
});
});
var errors = [];
var results = [];
// Execute all wrapped Promises
return Promise.all(resolvingPromises)
.then(function(items) {
items.forEach(function(payload) {
if (payload[1]) {
errors.push(payload[1]);
} else {
results.push(payload[0]);
}
});
return {
errors: errors,
results: results
};
});
}
var myPromises = [
Promise.resolve(1),
Promise.resolve(2),
Promise.reject(new Error('3')),
Promise.resolve(4),
Promise.reject(new Error('5'))
];
executeAllPromises(myPromises).then(function(items) {
// Result
var errors = items.errors.map(function(error) {
return error.message
}).join(',');
var results = items.results.join(',');
console.log(`Executed all ${myPromises.length} Promises:`);
console.log(`— ${items.results.length} Promises were successful: ${results}`);
console.log(`— ${items.errors.length} Promises failed: ${errors}`);
});
回答by MosheZada
ES2020introduces new method for the Promise type: Promise.allSettled()
Promise.allSettled gives you a signal when all the input promises are settled, which means they're either fulfilled or rejected. This is useful in cases where you don't care about the state of the promise, you just want to know when the work is done, regardless of whether it was successful.
ES2020为 Promise 类型引入了新方法:Promise.allSettled 在所有输入PromisePromise.allSettled()
都被解决时给你一个信号,这意味着它们要么被满足,要么被拒绝。这在您不关心 Promise 的状态,只想知道工作何时完成的情况下很有用,无论它是否成功。
const promises = [
fetch('/api-call-1'),
fetch('/api-call-2'),
fetch('/api-call-3'),
];
// Imagine some of these requests fail, and some succeed.
const result = await Promise.allSettled(promises);
console.log(result.map(x=>s.status));
// ['fulfilled', 'fulfilled', 'rejected']
Read more in the v8 blog post https://v8.dev/features/promise-combinators
在 v8 博客文章中阅读更多内容https://v8.dev/features/promise-combinator
回答by Herman
As @jib said,
正如@jib 所说,
Promise.allis all or nothing.
Promise.all全有或全无。
Though, you can control certain promises that are "allowed" to fail and we would like to proceed to .then.
但是,您可以控制某些“允许”失败的承诺,我们希望继续.then。
For example.
例如。
Promise.all([
doMustAsyncTask1,
doMustAsyncTask2,
doOptionalAsyncTask
.catch(err => {
if( /* err non-critical */) {
return
}
// if critical then fail
throw err
})
])
.then(([ mustRes1, mustRes2, optionalRes ]) => {
// proceed to work with results
})
回答by Nayan Patel
Using Async await -
使用异步等待 -
here one async function func1 is returning a resolved value, and func2 is throwing a error and returning a null in this situation, we can handle it how we want and return accordingly.
这里一个异步函数 func1 返回一个已解析的值,而 func2 在这种情况下抛出一个错误并返回一个 null,我们可以按照我们想要的方式处理它并相应地返回。
const callingFunction = async () => {
const manyPromises = await Promise.all([func1(), func2()]);
console.log(manyPromises);
}
const func1 = async () => {
return 'func1'
}
const func2 = async () => {
try {
let x;
if (!x) throw "x value not present"
} catch(err) {
return null
}
}
callingFunction();
Output is - [ 'func1', null ]
输出是 - [ 'func1', null ]
回答by Mohamed Mahmoud
if you get to use the q library https://github.com/kriskowal/qit has q.allSettled() method that can solve this problem you can handle every promise depending on its state either fullfiled or rejected so
如果你开始使用 q 库https://github.com/kriskowal/q它有 q.allSettled() 方法可以解决这个问题,你可以根据它的状态处理每个承诺,无论是完整的还是拒绝的
existingPromiseChain = existingPromiseChain.then(function() {
var arrayOfPromises = state.routes.map(function(route){
return route.handler.promiseHandler();
});
return q.allSettled(arrayOfPromises)
});
existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {
//so here you have all your promises the fulfilled and the rejected ones
// you can check the state of each promise
arrayResolved.forEach(function(item){
if(item.state === 'fulfilled'){ // 'rejected' for rejected promises
//do somthing
} else {
// do something else
}
})
// do stuff with my array of resolved promises, eventually ending with a res.send();
});
回答by Tyler Yasaka
For those using ES8 that stumble here, you can do something like the following, using async functions:
对于那些在这里绊倒的使用 ES8 的人,您可以使用异步函数执行以下操作:
var arrayOfPromises = state.routes.map(async function(route){
try {
return await route.handler.promiseHandler();
} catch(e) {
// Do something to handle the error.
// Errored promises will return whatever you return here (undefined if you don't return anything).
}
});
var resolvedPromises = await Promise.all(arrayOfPromises);
回答by Nayan Patel
We can handle the rejection at the individual promises level, so when we get the results in our result array, the array index which has been rejected will be undefined. We can handle that situation as needed, and use the remaining results.
我们可以在单个承诺级别处理拒绝,因此当我们在结果数组中获得结果时,被拒绝的数组索引将是undefined。我们可以根据需要处理这种情况,并使用剩余的结果。
Here I have rejected the first promise, so it comes as undefined, but we can use the result of the second promise, which is at index 1.
这里我拒绝了第一个承诺,所以它是未定义的,但我们可以使用第二个承诺的结果,它在索引 1 处。
const manyPromises = Promise.all([func1(), func2()]).then(result => {
console.log(result[0]); // undefined
console.log(result[1]); // func2
});
function func1() {
return new Promise( (res, rej) => rej('func1')).catch(err => {
console.log('error handled', err);
});
}
function func2() {
return new Promise( (res, rej) => setTimeout(() => res('func2'), 500) );
}
回答by Tom Auger
Have you considered Promise.prototype.finally()?
你考虑过Promise.prototype.finally()吗?
It seems to be designed to do exactly what you want - execute a function once all the promises have settled (resolved/rejected), regardless of some of the promises being rejected.
它似乎被设计为完全按照您的意愿执行 - 一旦所有承诺都已解决(已解决/拒绝),则执行一个函数,而不管某些承诺是否被拒绝。
From the MDN documentation:
从MDN 文档:
The finally()method can be useful if you want to do some processing or cleanup once the promise is settled, regardless of its outcome.
finally()如果您想在承诺完成后进行一些处理或清理,无论其结果如何,该方法都非常有用。
The finally()method is very similar to calling .then(onFinally, onFinally)however there are couple of differences:
该finally()方法与调用非常相似,.then(onFinally, onFinally)但有几个不同之处:
When creating a function inline, you can pass it once, instead of being forced to either declare it twice, or create a variable for it.
创建内联函数时,您可以传递一次,而不是被迫声明两次,或为其创建变量。
A finally callback will not receive any argument, since there's no reliable means of determining if the promise was fulfilled or rejected. This use case is for precisely when you do not care about the rejection reason, or the fulfillment value, and so there's no need to provide it.
finally 回调将不会收到任何参数,因为没有可靠的方法来确定承诺是被履行还是被拒绝。这个用例恰好适用于您不关心拒绝原因或履行值的情况,因此无需提供它。
Unlike Promise.resolve(2).then(() => {}, () => {})(which will be resolved with undefined), Promise.resolve(2).finally(() => {})will be resolved with 2.
Similarly, unlike Promise.reject(3).then(() => {}, () => {})(which will be fulfilled with undefined), Promise.reject(3).finally(() => {})will be rejected with 3.
不同Promise.resolve(2).then(() => {}, () => {})(将用 undefined 解决),Promise.resolve(2).finally(() => {})将用 2 解决。同样,不同Promise.reject(3).then(() => {}, () => {})(将用 undefined 完成),Promise.reject(3).finally(() => {})将用 3 拒绝。
== Fallback ==
== 回退 ==
If your version of JavaScript doesn't support Promise.prototype.finally()you can use this workaround from Jake Archibald: Promise.all(promises.map(p => p.catch(() => undefined)));
如果您的 JavaScript 版本不支持,Promise.prototype.finally()您可以使用Jake Archibald 的此解决方法:Promise.all(promises.map(p => p.catch(() => undefined)));

