【问题标题】:How to manage async function after/before loop [duplicate]如何在循环之后/之前管理异步功能[重复]
【发布时间】:2019-09-24 20:43:24
【问题描述】:

如何在异步循环后运行异步函数?循环不会返回承诺,这意味着您不能使用 await 语法来管理执行顺序。什么是像 Promise 一样管理循环的好方法。

这个问题发生在我的快速路由中。在使用循环从 reids DB 检索数据后,我尝试运行 res.json,但如果我只是将代码放在它之后,res.json 将在循环之前运行。在这里,我使用了一种愚蠢的方式。我检测到循环的最后一次迭代并运行我的 res.json 函数。我认为这不应该是解决这个问题的正确方法。

app.get('/redisApi/v0.3/users', (req, res) => {
  var users = [];
  redis.scan(0, 'MATCH', 'user:info:*', 'COUNT', 10000).then(key_res => {
    //where loop starts
    for (let i = 0; i < key_res[1].length; i++) {
      redis.hgetall(key_res[1][i]).then(user_res => {
        const newOBJ = Object.assign(user_res);
        users.push(newOBJ);
        //detect last iteration of the loop
        if (i === key_res[1].length - 1) {
          res.status(200).json({
            status: 'success',
            data: {
              users
            }
          });
        }
      });
    }
  });
});

寻找一种方法来管理循环的执行顺序。

【问题讨论】:

  • 不要使用循环,而是使用函数式编程和.map() 传递给Promise.all() 的一组承诺
  • 顺便说一句,Object.assign(user_res) === user_res。这不会创建新的对象引用。
  • 您可以将 res.status... 部分移到 for 循环之外,避免每次都检查它是否是最后一个。
  • @solarc 我试过了, res.status 会在循环之前运行。
  • @solarc 不,你不能。每次迭代的主体都发生在异步回调中。正如问题正确指出的那样,“之后”循环实际上并没有在迭代之后按顺序执行。

标签: javascript loops asynchronous


【解决方案1】:

我是这样写的:

app.get('/redisApi/v0.3/users', async (req, res) => {
  try {
    const key_res = await redis.scan(0, 'MATCH', 'user:info:*', 'COUNT', 10000);
    const users = await Promise.all(key_res[1].map(key => redis.hgetall(key)));

    res.status(200).json({ status: 'success', data: { users } });
  } catch (error) {
    res.status(500).json({ status: 'failure', data: { error } });
  }
});

注意.map()Promise.all() 的使用,以便同时异步await 每个请求。

不要忘记添加错误处理。您不想让 HTTP 请求挂起(双关语)

【讨论】:

  • 非常感谢!我发现许多类似的问题都有提示 Promise.all 和 map 函数的提示,但它们从未给出实际语法。
【解决方案2】:

有很多工具可以解决这个问题,这里有两个:

  1. 如果您想逐个触发异步调用,请等待最后一次调用,然后再进行下一次调用: 使用 Bluebird.js mapSeries。提供您的 key_res[1].length 作为要映射的数组,并将循环的逻辑作为映射函数。

  2. 如果您想一次性触发所有异步调用,但要等待所有调用完成: 只需将redis.hgetall 返回的promise 收集到一个新数组中,然后在这个数组上使用Promise.all

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-11
    • 2018-05-30
    • 1970-01-01
    • 2018-04-19
    • 2017-04-01
    • 1970-01-01
    • 2021-08-13
    • 2017-01-31
    相关资源
    最近更新 更多