【问题标题】:How do I make a forEach() with async/await fire synchronously not asynchronously?如何使用 async/await 同步而不是异步触发 forEach()?
【发布时间】:2017-09-17 22:25:04
【问题描述】:

我有以下代码:

console.log("TEST 1");
accounts.forEach(async function(account) {
    console.log("TEST 2");
    try {
        var data = await getReservations(account);
    } catch(err) {
        res.status(err.error_code).json(err);
    }
    console.log("TEST 3");
});
console.log("TEST 4");

当它运行时,控制台显示:

TEST 1
TEST 2
TEST 4
getReservations()
TEST 3

但我希望它等待getReservations() 完成,然后再继续通过forEach()。我希望它输出:

TEST 1
TEST 2
getReservations()
TEST 3
TEST 4

有什么想法吗?

【问题讨论】:

  • 您的问题可能已经回答here
  • 这是一个 for 循环比 .forEach 更好的地方
  • @Pyromonk - 这需要异步库而不是使用 async/await
  • @JaromandaX,谢谢。

标签: javascript promise


【解决方案1】:

要扩展其他答案,如果您真的想使用forEach,您可以编写自己的版本,我们将其称为forEachAsync

async function forEachAsync(array, fn, thisArg) {
  for (let i = 0; i < array.length; i++) 
    await fn.call(thisArg, array[i], i, array);
}

// Fake version of getReservations--just wait for a while.
function getReservations(account) {
  return new Promise(resolve => setTimeout(() => resolve(account), account));
}

const accounts = [1000, 500, 2000];  

console.log("TEST 1");
forEachAsync(accounts, async function(account) {
    console.log("TEST 2");
    var data = await getReservations(account);
    console.log("TEST 3", data);
})
.then(() => console.log("TEST 4"));

【讨论】:

    【解决方案2】:

    我不相信你可以,但是,下面的代码会起作用。

    (async function()
    {   
        console.log("TEST 1");
    
        for (let i = 0; i < accounts.length; ++i)
        {
            let account = accounts[i];
    
            console.log("TEST 2");
    
            try
            {
                var data = await getReservations(account);
            }
            catch (err)
            {
                res.status(err.error_code).json(err);
            }
    
            console.log("TEST 3");
        }
    
        console.log("TEST 4");
    })();
    

    【讨论】:

      【解决方案3】:

      这是一次常规 for 循环效果更好 - 下面的代码包装在 IIFE 中,因此可以使用 await

      var accounts = [1, 3];
      var getReservations = (account) => new Promise(resolve => setTimeout(resolve, 1000, account*2));
      (async function() {
          console.log("TEST 1");
          for(var i = 0, l = accounts.length; i < l; i++) {
              let account = accounts[i];
              console.log("TEST 2");
              try {
                  var data = await getReservations(account);
              } catch(err) {
                  console.error(err);
              }
              console.log("TEST 3");
          };
          console.log("TEST 4", data); // data should be 6
      })();

      注意:IIFE 之后的任何内容都不会“等待”

      【讨论】:

      • 感谢您的回答。这是我的 B 计划,但我希望有一种方法可以使用 forEach。感谢您的帮助。
      【解决方案4】:

      如果您乐于同时运行所有 getReservations 函数,您可以使用Promise.all()。例如:

      Promise.all(accounts.map(getReservations))
        .then(() => console.log('all get reservations completed'))
      

      或者,如果您需要按顺序完成对getReservations 的每个调用,您可以使用reduce() 构建一个承诺链。例如:

      accounts.reduce((p, account) => {
        return p.then(() => getReservations(account)
      }, Promise.resolve())
        .then(() => console.log('all get reservations completed'))
      

      【讨论】:

      • 但我认为他对如何使用 async/await 执行此操作很感兴趣。
      • 啊,真的。不过,我将把这个答案留在这里,因为它确实以另一种方式解决了他的问题。
      猜你喜欢
      • 1970-01-01
      • 2018-12-01
      • 2019-01-17
      • 2016-09-03
      • 2013-06-08
      • 1970-01-01
      • 2016-12-04
      • 2019-05-12
      • 2019-10-31
      相关资源
      最近更新 更多