首页 > 解决方案 > 如何使用异步减速器来构建一系列承诺?

问题描述

这是一个构建数据库查询的函数:

const buildDbQueries = async elements => elements.reduce(
  async (acc, element) => {
    // wait for the previous reducer iteration
    const { firstDbQueries, secondDbQueries } = await acc
    const asyncStuff = await someApi(element)

    // leave if the API does not return anything
    if (!asyncStuff) return { firstDbQueries, secondDbQueries }

    // async db query, returns a Promise
    const firstDbQuery = insertSomethingToDb({ 
      id: asyncStuff.id, 
      name: asyncStuff.name
    })

    // another async db query, returns a Promise 
    // have to run after the first one
    const secondDbQuery = insertAnotherthingToDb({
      id: element.id, 
      name: element.name,
      somethingId: asyncStuff.id
    })

    return {
      firstDbQueries: [...firstDbQueries, firstDbQuery],
      secondDbQueries: [...secondDbQueries, secondDbQuery]
    }
  },
  // initial value of the accumulator is a resolved promise
  Promise.resolve({
    firstDbQueries: [],
    secondDbQueries: []
  })
)

此函数返回不应执行的承诺,直到它们被解决。

现在我们使用那个函数

const myFunc = async elements => {

  const { firstDbQueries, secondDbQueries } = await buildDbQueries(elements)

  // we don't want any query to run before this point

  await Promise.all(firstDbQueries)
  console.log('Done with the first queries')

  await Promise.all(secondDbQueries)
  console.log('Done with the second queries')
}

问题是:


编辑

正如评论中所建议的那样,我尝试不使用reduce,而是使用for … of循环。

const buildDbQueries = async elements => {
  const firstDbQueries = []
  const secondDbQueries = []

  for (const element of elements) {
    const asyncStuff = await someApi(element)

    // leave if the API does not return anything
    if (!asyncStuff) continue

    // async db query, returns a Promise
    const firstDbQuery = insertSomethingToDb({ 
      id: asyncStuff.id, 
      name: asyncStuff.name
    })

    // another async db query, returns a Promise 
    // have to run after the first one
    const secondDbQuery = insertAnotherthingToDb({
      id: element.id, 
      name: element.name,
      somethingId: asyncStuff.id
    })

    firstDbQueries.push(firstDbQuery)
    secondDbQueries.push(secondDbQuery)

  }

  return { firstDbQueries, secondDbQueries }
}

这仍然会产生与以前版本完全相同的问题reduce

标签: javascript

解决方案


不要使用async减速机。特别是不要建立一系列承诺。或者一系列稍后运行的东西。这在很多层面上都是错误的。

我猜你正在寻找类似的东西

function buildDbQueries(elements) {
  return elements.map(element =>
    async () => {
      const asyncStuff = await someApi(element)
      // leave if the api doesn't return anything
      if (!asyncStuff) return;

      await insertSomethingToDb({ 
        id: asyncStuff.id, 
        name: asyncStuff.name
      });
      return () =>
        insertAnotherthingToDb({
          id: element.id, 
          name: element.name,
          somethingId: asyncStuff.id
        })
      ;
    }
  );
}

async function myFunc(elements) {
  const firstQueries = buildDbQueries(elements)

  // we don't want any query to run before this point

  const secondQueries = await Promise.all(firstQueries.map(query => query()));
  //                              this call actually runs the query ^^^^^^^
  console.log('Done with the first queries');

  await Promise.all(secondQueries.map(query => query()));
  //         this call actually runs the query ^^^^^^^
  console.log('Done with the second queries')
}

推荐阅读