【问题标题】:How to iterate multiple async await functions and chain together in JavaScript?如何在 JavaScript 中迭代多个异步等待函数并链接在一起?
【发布时间】:2019-08-16 23:00:22
【问题描述】:

我是 JavaScript 和 Node.js 的新手。我有以下代码:

  const populateSetup = async () => {
  token = await getToken();

  const promises = await constant.accounts.map(async (x) => {
    const accountId = await createAccountRequest(x.account);
    const peoid = await createPeopleRequests(x.people);
    const pid = await createProjectsRequests(x.project);

    return [accountId, pid, peoid];
  });

  const [accountId, pid, peoid] = await Promise.all(promises);
};

在上面,首先获取token并需要创建帐户,然后需要返回accountId来创建人员和项目。假设我有以下输入:

    exports.accounts = [
  { account: this.testAccountFirst, project: this.projectOne, people: this.testUserOne },
  { account: this.testAccountSecond, project: this.projectTwo, people: this.testUserTwo },
];

在节点环境中运行populateSetup() 后,我的结果是(不是控制台输出,而是populateSetup() 的输出:

testAccountFirst has 1 people -> testUserOne
testAccountSecond has 2 projects and 1 user -> projectOne, projectTwo, testUserTwo

预期结果是:

testAccountFirst should have 1 project and 1 people -> projectOne, testUserOne
testAccountSecond should have 1 project and 1 people -> projectTwo, testUserTwo

这里的问题是第一个帐户的accountId没有发送到projectsRequest。我不知道如何解决这个问题。我已经通过了这个Stackoverflow question,但仍然无法弄清楚。

【问题讨论】:

  • 您的await promise.all() 是一个数组,其中数组中的每个元素都是[accountId, pid, peoid].map() 也并行运行所有异步操作。直到第一次迭代完成后,第二次迭代才开始。如果您想一次运行它们一次迭代,请使用常规的 for 循环。
  • 感谢 @jfriend00 使用 for loop 为我工作。
  • 虽然答案是正确的并且 for-loop 是解决方案之一,但我很难相信console.log(accountId, pid, peoid); 在任何情况下都会打印testAccountFirst, testUserOne。即使其中一个是undefined,它将始终打印 3 个值,空格分隔。从来没有 4,也没有逗号。请更新您的问题,以便下一个阅读它的人不会感到困惑。
  • @AlexPakka - 编辑了我的问题,对此感到抱歉

标签: javascript node.js


【解决方案1】:

我很难准确理解您要问的问题,但.map() 并不精通异步。这意味着即使您将回调声明为async.map() 也不会对返回的承诺做任何事情,因此它不会在第一次迭代完成之前等待开始第二次迭代。因此,您最终会并行运行循环的所有迭代中的所有异步操作,并且它们可以以任意随机顺序完成。

如果您真的想一个接一个地按顺序运行它们,那么将您的.map() 切换到for 循环,因为for 循环将在循环的第一次迭代中等待await,然后再开始循环的第二次迭代等等......

【讨论】:

  • 是的,我正在寻找顺序执行,因为一个的返回取决于另一个。 For 循环确实对我有用。
【解决方案2】:

return [accountId, pid, peoid]; 正在返回已解决的承诺,此外,您等待一个又一个承诺解决。比如一个解析是5秒,那么你需要等待5+5+5=15秒

但更重要的是,使用带有 Promise 的 .map() 是不好的做法,因为它是 sync 运算符。 在你的情况下,我会使用类似的东西:

const populateSetup = async () => {
  const token = await getToken();

  const [accountId, peoid, pid] =[
    createAccountRequest(x.account),
    createPeopleRequests(x.people),
    createProjectsRequests(x.project)
  ]

  return Promise.all([accountId, peoid,pid])
};

这里,你返回 promise,可以这样使用:

const [accountId, peoid,pid] = await populateSetup()

Promise.all() 承诺同时执行并等待所有解决,所以它是 5 秒而不是 15 秒

【讨论】:

  • 谢谢 我明白你的意思。就我而言,我正在寻找顺序执行,所以Promise 似乎对我不起作用。
猜你喜欢
  • 2019-11-17
  • 2021-01-24
  • 2017-01-15
  • 1970-01-01
  • 1970-01-01
  • 2020-03-07
  • 2020-10-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多