JavaScript Promise.all 是否具有在成功和失败时触发的回调
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32978838/
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
Does JavaScript Promise.all have a callback that is fired when there are success AND failures
提问by Taysky
Am I misunderstanding Promise.all? I have X promises in an array and i'm trying to aggregate the success/failure ratio of the array.
我误解了 Promise.all 吗?我在数组中有 X 承诺,我正在尝试汇总数组的成功/失败率。
Here is what I think I know:
以下是我认为我知道的:
Promise.all takes an array of promises.
Promise.all 接受一系列承诺。
If all of the promises succeed then the .then
callback is ran.
如果所有承诺都成功,则.then
运行回调。
If one of the promises fail then the .catch
callback is called and the argument passed in is the value of the single raised error.
如果承诺之一失败,则.catch
调用回调,传入的参数是单个引发错误的值。
There is no callback fired which is the result of all the promises if some succeed and some fail. I.e. it can't give you an array like (pseudo code) [success, fail, success, success]
- like one would expect and one can find in many JS libraries (ajax, ember, etc).
如果有些成功有些失败,则不会触发回调,这是所有承诺的结果。即它不能给你一个像(伪代码)[success, fail, success, success]
这样的数组——就像人们期望的那样,并且可以在许多 JS 库(ajax、ember 等)中找到。
It's like the .then
is more like a .success
, not a function that always runs after all the promises are fulfilled regardless of whether some succeeded or some failed.Why doesn't have a .when
.finally
.runThisShizNoMatterWhat
?? Or am I missing something (very probable)?
就像 更像.then
是一个.success
,而不是一个在所有承诺都完成后总是运行的函数,无论一些成功还是失败。为什么没有.when
.finally
.runThisShizNoMatterWhat
??或者我错过了什么(很可能)?
回答by loganfsmyth
This is related to Bluebird Promise.all - multiple promises completed aggregating success and rejections, but that's Bluebird-specific. The core of the issue is that if you want to inspect whether something succeeded or failed, then you aren't really asking for the direct result of each promise. Instead, you'd want to transform the promises before using Promise.all
. There is no helper for this ES6-standard promises, but it is trivial to implement. In most libraries, this is known as Promise.settle
. For example
这与Bluebird Promise.all相关- 多个承诺完成聚合成功和拒绝,但这是 Bluebird 特定的。问题的核心是,如果您想检查某事是成功还是失败,那么您并不是真正要求每个承诺的直接结果。相反,您希望在使用Promise.all
. 这个 ES6 标准的承诺没有帮助,但实现起来很简单。在大多数库中,这称为Promise.settle
. 例如
var someThings = [...]; // some list of promises that may succeed or fail
settle(someThings).then(results => {
results.forEach(result => {
if (result.state === 'fullfilled'){
console.log('succeeded', result.value);
} else {
console.log('failed', result.value);
}
});
});
function settle(arr){
return Promise.all(arr.map(promise => {
return promise.then(
value => ({state: 'fullfilled', value}),
value => ({state: 'rejected', value})
);
}));
}
回答by MinusFour
If one of the promises rejects, then the promise returned by Promise.all
is rejected. So the rejection handler will be called right after one of the promises rejection. This might not be the desired behaviour if you just want to run all Promises without worrying about rejections (i.e. don't reject the promise if any promise rejects).
如果其中一个promise被拒绝,则返回的promisePromise.all
被拒绝。所以拒绝处理程序将在承诺拒绝之一之后被调用。如果您只想运行所有 Promise 而不必担心被拒绝(即,如果任何 Promise 被拒绝,则不要拒绝该承诺),这可能不是您想要的行为。
You can still handle each individual promise rejection so it will fulfill after the rejection.
您仍然可以处理每个单独的承诺拒绝,以便在拒绝后履行。
var promiseRejected = new Promise(function(resolve, reject){
setTimeout(function(){
reject('I was rejected');
}, 1000);
});
promiseRejected = promiseRejected.then(null, function(reason){
//I was rejected, now lets fullfill it.
return reason;
});
var promiseResolved = new Promise(function(resolve, reject){
setTimeout(function(){
resolve('All good');
}, 1500);
});
var time = performance.now();
Promise.all([promiseRejected, promiseResolved]).then(function(results){
//both promises fulfilled; 1500 msecs passed
console.log(results[0], results[1], performance.now() - time);
});
A promise constructor that resolves when all promises have been resolved/rejected example:
当所有承诺都已解决/拒绝时解决的承诺构造函数示例:
Promise.when = function (arrPromises) {
if (!Array.isArray(arrPromises)) {
return new TypeError('Expecting an Array of Promises');
}
return new Promise(function (resolve, reject) {
var len = arrPromises.length,
values = [],
settled = 0;
function settle(value, index) {
values[index] = value;
settled++;
if (len === settled) {
resolve(values);
}
}
if (len === 0) {
resolve([]);
} else {
arrPromises.forEach(function (promise, index) {
var handler = function (value) {
settle(value, index);
};
promise.then(handler, handler);
});
}
});
}
回答by jib
If you're fine telling errors apart from your values, then doing what you want is as simple as:
如果除了价值观之外,您还可以说出错误,那么做您想做的事情就很简单:
Promise.all(array.map(promise => promise.catch(error => error)))
var log = msg => div.innerHTML += "<p>" + msg + "</p>";
var a = () => Promise.resolve(1);
var b = () => Promise.reject("error");
var c = () => Promise.resolve(3);
Promise.all([a(), b(), c()].map(p => p.catch(e => e))).then(r => log(r));
<div id="div"></div>
回答by kraf
Promise.all
creates a new promise that can only either be resolved or rejected as a whole. Maybe you can think of it as having the every
array method semantics which comes back with false when the first element doesn't match the predicate.
Promise.all
创建一个只能作为整体解决或拒绝的新承诺。也许您可以将其视为具有every
数组方法语义,当第一个元素与谓词不匹配时,该语义会返回 false。
The then
function takes up to two arguments, the second being the rejected handler. In this sense it's more than just a success
, it can actually handle all cases. The catch
is only a convenience method, short for .then(undefined, function(reason) { ... })
.
该then
函数最多接受两个参数,第二个是被拒绝的处理程序。从这个意义上说,它不仅仅是一个success
,它实际上可以处理所有情况。的catch
是只有一个方便的方法,简称.then(undefined, function(reason) { ... })
。
The promise API does not have what you need I'm afraid, you would have to implement it yourself.
恐怕承诺 API 没有您需要的东西,您必须自己实现它。
回答by vitaly-t
From your question it seems that you are expecting to settle all the promises, which method promise.all
doesn't guarantee, only method promise.settle
guarantees to settle each promise in the array.
从您的问题来看,您似乎希望解决所有承诺,哪个方法promise.all
不保证,只有方法promise.settle
保证解决数组中的每个承诺。
If you want the result of promise.all
, while also settling each promise, plus have a notification of which promise resolved or rejected, then method spex.batchis exactly what you need.
如果您想要 的结果promise.all
,同时还解决每个承诺,并获得解决或拒绝承诺的通知,那么方法spex.batch正是您所需要的。
Example as copied from Batch Processing:
从批处理复制的示例:
var spex = require('spex')(Promise);
// function that returns a promise;
function getWord() {
return Promise.resolve("World");
}
// function that returns a value;
function getExcl() {
return '!';
}
// function that returns another function;
function nested() {
return getExcl;
}
var values = [
123,
"Hello",
getWord,
Promise.resolve(nested)
];
spex.batch(values)
.then(function (data) {
console.log("DATA:", data);
}, function (reason) {
console.log("REASON:", reason);
});
This outputs:
这输出:
DATA: [ 123, 'Hello', 'World', '!' ]
Now let's make it fail by changing getWord
to this:
现在让我们通过改变getWord
这个来让它失败:
function getWord() {
return Promise.reject("World");
}
Now the output is:
现在输出是:
REASON: [ { success: true, result: 123 },
{ success: true, result: 'Hello' },
{ success: false, result: 'World' },
{ success: true, result: '!' } ]
i.e. the entire array is settled, reporting index-bound results.
即整个数组已解决,报告索引绑定结果。
And if instead of reporting the entire reason we call getErrors()
:
如果不是报告我们调用的全部原因getErrors()
:
console.log("REASON:", reason.getErrors());
then the output will be:
那么输出将是:
REASON: [ 'World' ]
This is just to simplify quick access to the list of errors that occurred.
这只是为了简化对发生的错误列表的快速访问。
And you can see from the method's protocolthat you can pass in optional cb
- callback parameter that will be telling you which of the promises resolved and which ones rejected.
您可以从方法的协议中看到,您可以传入可选的cb
- 回调参数,该参数将告诉您哪些承诺已解决,哪些承诺被拒绝。
回答by granmoe
I agree that using Bluebird.reflect to implement settle is the best way, if you are using Bluebird. Here is another solution that may be good depending upon your use case. It worked for me in a somewhat interesting situation. This also assumes Bluebird as the promise library.
如果您使用 Bluebird,我同意使用 Bluebird.reflect 来实现结算是最好的方法。这是另一种可能有用的解决方案,具体取决于您的用例。它在一个有点有趣的情况下对我有用。这也假设 Bluebird 作为承诺库。
In my case, I have an array of functions ("tasks") which are all wrapped in Promise.method. These tasks may return a rejected promise or they may return or throw plain values that will become promise resolutions. I needed to execute all of these and collect all results (not just first failure).
就我而言,我有一组函数(“任务”),它们都包含在 Promise.method 中。这些任务可能会返回一个被拒绝的承诺,或者他们可能会返回或抛出将成为承诺解决方案的普通值。我需要执行所有这些并收集所有结果(不仅仅是第一次失败)。
Again, bear in mind that each item in the tasks array is a Promise.method wrapped function. (Easy to implement. See http://bluebirdjs.com/docs/api/promise.method.html)
再次记住,tasks 数组中的每一项都是一个 Promise.method 包装函数。(易于实施。参见http://bluebirdjs.com/docs/api/promise.method.html)
var runTasks = function(tasks) {
return Bluebird.reduce(tasks, function (results, task) {
return task()
.then(function (result) {
results.success.push(result)
return results
})
.caught(function (result) {
results.fail.push(result)
return results
})
}, { success: [], fail: [] })
}
You would then call it like this, getting back an object that has an array of fulfilled values and an array of rejected values:
然后,您可以这样调用它,取回一个对象,该对象具有一组已完成值和一组拒绝值:
runTasks(taskArray)
.then(function(results){
// do whatever you want here
// results.success is an array of the returned/resolved values
// results.fail is an array of the rejected/thrown values
})