【问题标题】:How to approach multiple async calls on single array?如何处理单个数组上的多个异步调用?
【发布时间】:2020-10-02 10:37:47
【问题描述】:

这是一个更理论的问题。我原本打算将这个问题称为是否可以对 map 进行两次迭代,但仅从它的声音来看,这听起来像是一种反模式。所以我想我只是在接近这个错误。

另请注意:这里的数据作为抽象服务器。我知道我在这里使用此处提供的数据所做的事情是不必要的,但是请不要过分关注数据结构等等。它不代表我正在使用的真实数据(更复杂,而且由客户提供,我无法更改)。而是将问题作为如何为每个数组项返回结构化异步调用来解决! :-)


我的问题归结为:

  • 我有 ids 数组,我需要在其上执行两个单独的异步调用
  • 这两个调用都需要通过(并且在所有 id 实例中)

举个例子,假设我有这两个数据集:

const dataMessages = [
  { id: "a", value: "hello" }, 
  { id: "b", value: "world" }
];

const dataNames = [
  { id: "a", name: "Samuel" },
  { id: "b", name: "John" },
  { id: "c", name: "Gustav"},
];

还有一个 API 调用模型:

const fetchFor = async (collection: Object[], id: string): Promise<Object> => {
  const user = collection.find(user => user.id === id);
  if (!user) {
    throw Error(`User ${id} not found`);
  }
  return user;
};

现在我需要为两个数据集调用fetchFor() 函数,大​​概在Promise.all 内部,因为forEach 与@987654330 的预定数组不是异步的@s.

我正在考虑类似于 map 的 Promise 列表以供 Promise.all 执行。当您只需要映射一个 api 调用时,这很好用:

const run = async () => {
  const result = await Promise.all(
    ['a', 'b'].map(id => fetchFor(dataMessages, id)
  )
  console.log(result) // [{id: 'a', value: 'hello'}, {id: 'b', value: 'world}]
}

但是我不知何故需要返回两个承诺

  • fetchFor(dataMessages, id)
  • fetchFor(dataNames, id)

Promise.all Promises 数组中。


我想我总是可以简单地为两个 API 调用实例做两个映射的flatMap,但这听起来有点愚蠢,因为

  • 我会在同一个数组上执行 array.map 两次
  • 我的数据结构没有逻辑连接(同一用户的两个单独的数组项,甚至不会互相跟随)

所以理想情况下我想以

的形式返回 dat
 const result = await Promise.all([...])
 console.log(result)
 /* [
 *   {id: 'a', message: 'hello', name: 'Samuel'},
 *   {id: 'b', message: 'world', name: 'John'},
 *  ]

或者我是否只需要对 Promise 进行平面映射,然后在已解析的 Promise.all 上的单独处理程序中根据 id 标识符对对象进行数据合并?

我在此处提供了单 api-call 模型的工作示例,因此您不必复制粘贴。

解决此类问题的正确/常用方法是什么?

【问题讨论】:

  • 您为什么需要致电fetchFor(dataMessages, id)?您是否只需将id 的消息添加到user(如果有的话)?
  • @Andreas 不。我知道在示例中它是有道理的,但不要将消息 / id 视为实际数据库中的数据字段(显然实际上我返回的不仅仅是一个字段)。我只是选择了这两件事作为问题的抽象,作为我必须做的(更复杂的)事情的表示。问题是关于在单个地图中返回两个结构化 Promise,所以不要过分关注数据结构的正确性以及其他问题:-)

标签: javascript typescript asynchronous async-await es6-promise


【解决方案1】:

您可以嵌套Promise.all 调用:

const [messages, names] = await Promise.all([
  Promise.all(
    ['a', 'b'].map(id => fetchFor(dataMessages, id)
  ),
  Promise.all(
    ['a', 'b', 'c'].map(id => fetchFor(dataNames, id)
  )
]);

如果您想在检索后合并结果,这只是标准数据操作的问题。

【讨论】:

  • 哦,是的,现在我回过头来看,我有点困惑,我怎么没想到Promise.all 两个 Promise 可以作为参数数组的元素另一个Promise.all,整洁:-)!
  • 最后一件事,经过我自己的一些研究,我发现你也可以使用 for of 和两个异步调用,但如果我理解正确,Promise.all 方法更好,因为它可以同时运行,因此处理大量数据时速度更快,对吧?
猜你喜欢
  • 2011-03-18
  • 2010-12-26
  • 1970-01-01
  • 1970-01-01
  • 2015-05-02
  • 2014-04-10
  • 2019-05-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多