简体   繁体   English

Promise.all()未按预期顺序解决承诺

[英]Promise.all() is not resolving promises in the expected order

If I understand Promise.all() correctly, I would expect this code to take 5 seconds before outputting only the 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, then the final promise rejects. 相反,前两个承诺会解决, 然后最后的承诺会被拒绝。 Additionally, the first two promises aren't even resolving in the order in which they are passed in to Promise.all(). 此外,前两个承诺甚至没有按照它们传递给Promise.all()的顺序进行解析。 Do I need to compose my promises differently to see the behavior I'm expecting? 我是否需要以不同的方式履行诺言才能看到我期望的行为?

Edited 编辑

Promise.all() does indeed wait until all the promises in the iterable passed into it resolve. Promise.all()确实确实要等到传递给它的可迭代对象中的所有promise都解决为止。 My first clue was the fact that the console was outputting undefined (thanks Jaromanda X). 我的第一个线索是控制台输出未定义的事实(感谢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: 如果我删除对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. Promise.all()拒绝其他承诺,即使它们比被拒绝的承诺更早解决。 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. 是的,由Promise.all()解析的值将与作为参数传入的iterable中的promise的顺序相同。 Thanks for all your help! 感谢你的帮助!

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. 正是我们想要的。

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. Promise.all的thencatch函数仅在所有承诺均已解决或其中一个承诺被拒绝后才被调用。 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) 各个承诺可以按任何顺序解决(这就是承诺的全部内容-它们是异步的,可以根据需要完成它们应做的工作)

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. 您可能会在promise中混入console.logs, thenthen回调中混入console.logs。

Promise.all does not impose any order on the promises, they fulfill when they fulfill Promise.all不会对诺言施加任何顺序,它们会在履行时履行

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秒

Just to add to what others have said. 只是为了补充别人所说的话。

Promise.all does 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) => {

});

Promise.all runs all Promises that you pass it in parallel. Promise.all运行您传递的所有Promise.all 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. 您需要等待两者都完成,但是同时启动两者将使等待时间减少大约一半。

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). 如果您希望从所有三个调用中返回汇总数据,则还需要修改您的Promise以在数组(或对象)中返回其值。 For example: 例如:

  • firstAsyncFunction takes userId and returns { name: 'Bob' } firstAsyncFunction使用userId并返回{ name: 'Bob' }
  • secondAsyncFunction takes userObject and returns { name: 'Bob', car: 'Porsche' } secondAsyncFunction接受userObject并返回{ name: 'Bob', car: 'Porsche' }
  • thirdAsyncFunction takes userObject and returns { name: 'Bob', car: 'Porsche', kids: 5 } thirdAsyncFunction接受userObject并返回{ name: 'Bob', car: 'Porsche', kids: 5 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM