javascript Promise.all() 没有按照预期的顺序解决承诺
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31893915/
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
Promise.all() is not resolving promises in the expected order
提问by James Hines
If I understand Promise.all() correctly, I would expect this code to take 5 seconds before outputting onlythe reason for the rejected promise to the console.
如果我没有理解Promise.all()正确,我希望在输出之前该代码,以5秒只为拒绝承诺到控制台的原因。
function firstAsyncFunction() {
return new Promise(function(resolve, reject){
setTimeout(function(){
resolve(console.log('First async function has been resolved!'));
}, 500);
});
}
function secondAsyncFunction() {
return new Promise(function(resolve, reject) {
setTimeout(function(){
resolve(console.log('Second async function has been resolved!'));
}, 2000);
});
}
function thirdAsyncFunction() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
reject('Internal server error'); // rejected for some reason
}, 5000);
});
};
Promise.all([secondAsyncFunction(), firstAsyncFunction(), thirdAsyncFunction()])
.then(function(values){
values.forEach(function(value){
console.log(value);
});
}).catch(function(err){
console.log(err);
});
Instead, the first two promises resolve, thenthe final promise rejects. Additionally, the first two promises aren't even resolving in the order in which they are passed in to Promise.all(). Do I need to compose my promises differently to see the behavior I'm expecting?
相反,前两个承诺会解决,然后最后的承诺会拒绝。此外,前两个 Promise 甚至没有按照它们传入 Promise.all() 的顺序进行解析。我是否需要以不同的方式撰写我的承诺才能看到我期望的行为?
Edited
已编辑
Promise.all() does indeed wait until all the promises in the iterable passed into it resolve. My first clue was the fact that the console was outputting undefined (thanks Jaromanda X). If I remove the calls to console.log() in the resolve to firstAsyncFunction() and secondAsyncFunction() the following piece of code works exactly as I would expect:
Promise.all() 确实会等到传递给它的 iterable 中的所有承诺解决。我的第一个线索是控制台输出 undefined(感谢 Jaromanda X)。如果我在对 firstAsyncFunction() 和 secondAsyncFunction() 的解析中删除对 console.log() 的调用,则以下代码完全按照我的预期工作:
function firstAsyncFunction() {
return new Promise(function(resolve, reject){
setTimeout(function(){
resolve('First async function has been resolved!');
}, 1000);
});
}
function secondAsyncFunction() {
return new Promise(function(resolve, reject) {
resolve('Second async function has been resolved!');
});
}
function thirdAsyncFunction() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
reject('Internal server error');
}, 5000);
});
};
Promise.all([
thirdAsyncFunction(),
firstAsyncFunction(),
secondAsyncFunction()
])
.then(function(values){
values.forEach(function(value){
console.log(value);
});
})
.catch(function(err){
console.log(err);
});
After five seconds I see "Internal server error" only. Promise.all() rejects the other promises even though they resolve sooner than the promise that was rejected. And yes, the values resolved by Promise.all() will be in the same order as the promises in the iterable passed in as a parameter. Thanks for all your help!
五秒钟后,我只看到“内部服务器错误”。Promise.all() 拒绝其他承诺,即使它们比被拒绝的承诺更快解决。是的,由 Promise.all() 解析的值将与作为参数传入的可迭代对象中的 Promise 的顺序相同。感谢你的帮助!
One more example:
再举一个例子:
function firstAsyncFunction() {
return new Promise(function(resolve, reject){
setTimeout(function(){
resolve('First async function has been resolved!');
}, 1000);
});
}
function secondAsyncFunction() {
return new Promise(function(resolve, reject) {
resolve('Second async function has been resolved!');
});
}
function thirdAsyncFunction() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve({
users: [
{ name: 'Ronnie', age: 22 },
{ name: 'Bobby', age: 21 },
{ name: 'Ricky', age: 21 },
{ name: 'Mike', age: 20 }
]
});
}, 5000);
});
};
Promise.all([thirdAsyncFunction(), firstAsyncFunction(), secondAsyncFunction()])
.then(function(values){
values.forEach(function(value){
console.log(value);
});
})
.catch(function(err){
console.log(err);
});
After five seconds, this code will output:
五秒后,此代码将输出:
{ users:
[ { name: 'Ronnie', age: 22 },
{ name: 'Bobby', age: 21 },
{ name: 'Ricky', age: 21 },
{ name: 'Mike', age: 20 } ] }
First async function has been resolved!
Second async function has been resolved!
Exactly what we want.
正是我们想要的。
采纳答案by Jaromanda X
Promise.all does not impose any order on the promises, they fulfill when they fulfill
Promise.all 不会对 Promise 强加任何顺序,它们在履行时履行
the third promise "rejects" well after the other two "resolve", so the fact that the first two are resolved before the last is rejected is to be expected
第三个承诺在其他两个“解决”之后“拒绝”,所以前两个在最后一个被拒绝之前解决的事实是可以预料的
by the way, your first two promises are resolving the value undefined
and outputting to the console - which is why you may think that Promise.all is doing something it ought not be doing
顺便说一句,您的前两个承诺正在解析值undefined
并输出到控制台 - 这就是为什么您可能认为 Promise.all 正在做它不应该做的事情
Do I need to compose my promises differently to see the behavior I'm expecting?
我是否需要以不同的方式撰写我的承诺才能看到我期望的行为?
You wont get exactly the behaviour you are expecting, because you expect the promises to resolve in a particular order, the only way that can happen is for the promise to wait for the previous one to be fulfilled before it can fulfill, so the time would be cumulative, not in parallel, so in that case you wont get the rejection for 7.5 seconds rather than the 5 seconds you "expect"
你不会得到你所期望的行为,因为你期望承诺以特定的顺序解决,唯一可能发生的方法是承诺等待前一个完成后才能实现,所以时间会是累积的,而不是并行的,所以在这种情况下,你不会得到 7.5 秒的拒绝,而不是你“期望”的 5 秒
回答by potatopeelings
The then
or the catch
function of Promise.all is called only once all of the promises have resolved or one of the promises has been rejected. The individual promises can resolve in any order (that's the entire point of promises - they are asynchronous and can complete what they are supposed to whenever they like)
Promise.all的then
orcatch
函数仅在所有承诺都已解决或其中一个承诺已被拒绝时才被调用。单个承诺可以按任何顺序解决(这就是承诺的全部内容——它们是异步的,可以随时完成他们应该做的事情)
That said, it would be clearer if you tagged your Promise.all console.log differently, like so
也就是说,如果你以不同的方式标记你的 Promise.all console.log 会更清楚,像这样
Promise.all([secondAsyncFunction(), firstAsyncFunction(), thirdAsyncFunction()])
.then(function (values) {
values.forEach(function (value) {
console.log('then:' + value);
});
}).catch(function (err) {
console.log(err);
});
You could be mixing up the console.logs in the promise and the one in the then
callback.
您可能会混淆承诺中的 console.logs 和then
回调中的一个。
回答by Bodman
Just to add to what others have said.
只是为了补充其他人所说的。
Promise.alldoes not run sequentially.
Promise.all不会按顺序运行。
Here is an example of running async functions sequentially in ES6
这是在 ES6 中按顺序运行异步函数的示例
/**
* Runs async functions sequentially
* @param Function[]
* @return Promise<any>
*/
function runSequentially(functions) {
return functions.reduce((promise, next) => {
return promise.then(next);
}, Promise.resolve());
}
/**
* Full Example
*/
function foo()
{
return new Promise(( resolve, reject )=>{
resolve();
})
}
function boo() {
return new Promise((resolve, reject) => {
resolve();
})
}
function baz() {
return new Promise((resolve, reject) => {
resolve();
})
}
const functions = [foo, boo, baz];
runSequentially(functions).then((result) => {
}).catch((error) => {
});
回答by rrowland
Promise.all
runs all Promises that you pass it in parallel. This is useful when the Promises don't depend on each other and you need to perform both. For instance, in an integration test where you need to register two clients with a server. You need to wait for both to finish, but launching both at the same time will cut your wait roughly in half.
Promise.all
运行您并行传递的所有承诺。当 Promise 不相互依赖并且您需要同时执行两者时,这很有用。例如,在需要向服务器注册两个客户端的集成测试中。您需要等待两者都完成,但同时启动它们会将您的等待时间减少大约一半。
If you want to run them sequentially, you could chain your Promises, returning the result from one to the next:
如果你想按顺序运行它们,你可以链接你的 Promises,将结果从一个返回到下一个:
firstAsyncFunction
.then(secondAsyncFunction)
.then(thirdAsyncFunction)
.then(function(values) {
console.log(values)
}, function(err) {
console.log(err);
});
If you're looking to return aggregated data from all three calls, you'd also want to modify your promises to return their value in an array (or object). For example:
如果您希望从所有三个调用中返回聚合数据,您还需要修改您的承诺以在数组(或对象)中返回它们的值。例如:
- firstAsyncFunction takes
userId
and returns{ name: 'Bob' }
- secondAsyncFunction takes
userObject
and returns{ name: 'Bob', car: 'Porsche' }
- thirdAsyncFunction takes
userObject
and returns{ name: 'Bob', car: 'Porsche', kids: 5 }
- firstAsyncFunction 接受
userId
并返回{ name: 'Bob' }
- secondAsyncFunction 接受
userObject
并返回{ name: 'Bob', car: 'Porsche' }
- 第三个异步函数接受
userObject
并返回{ name: 'Bob', car: 'Porsche', kids: 5 }