await promise.all 链式数组方法

await promise.all chained array-methods

我需要递归调用 API 遍历子条目,然后 return 筛选结果,然后再继续。我最初将结果放在一个数组中,然后执行 .forEach,如果我找到一个匹配项,我需要递归这样做;但是,由于 的答案中描述的问题,这没有用。所以,我试着修改了那个问题的答案,但还是没等到。

const getDatabases = async (blockId) => {
  let databases = [];
  let childDatabases = [];
    
  const children = await getChildren(blockId);
  Promise.all(children.results
    .filter( (child) => {
      return (['child_database', 'database'].includes(child.type)
        || child.has_children === true);
    })
    .map( async (child) => {
      if (['child_database', 'database'].includes(child.type)) {
        return { id: child.id, title: child.child_database.title };
      } else {
        console.log(`Waiting on getDatabases for ${child.id}`); // 1
        childDatabases = await getDatabases(child.id);
        return false;
      }
    })  
  )
    .then((childDbs) => {
      console.log(`Got childDbs`); // 3, 4
      databases = 
        [...databases, ...childDatabases].filter(dbId => dbId !== false);
      return databases;
    })
    .catch((err) => console.log(err));

}

app.get('/api', async (req, res) => {
  const dashboardPage = await getDashboardPage();
  const databases = await getDatabases(dashboardPage);
  console.log('No longer awaiting getDatabases'); // 2
  ...
}

那么问题来了,为什么 2 出现在 3 和 4 之前,而不是在它们之后? 2 之前的 const databases = await getDatabases(dashboardPage); 不应该等待 1 之后通过 childDatabases = await getDatabases(child.id); 的所有递归调用吗?

直接的答案是我需要 await Promise.all。否则,Promise.all 在到达 .then 之前挂出并等待其中的 async/await,但父函数只是触发了这些承诺和 returns没什么,因为没有人告诉它等待。所以,简单地说,

const getDatabases = async (blockId) => {
  let databases = [];
  let dbsOfChildren = [];

  const children = await getChildren(blockId);
  await Promise.all(children.results
    .filter( (child) => {

值得注意的是,出于类似的原因,不能在 async 之后链接更多的数组方法。否则,下一个链式方法将立即传递一个数组……未解决的承诺。所以,你不能,例如,

  await Promise.all(myArray
    .filter( (e) => {
      // do stuff
    })
    .map( async (e) => { 
      // do some async stuff
    })
    .filter( // filter ); // <-- this won't work
  )

相反,您需要等待 promise 解决,然后再进行额外的操作,因此您将其放入 .then:

  await Promise.all(myArray
    .filter( (e) => {
      // do stuff
    })
    .map( async (e) => { 
      // do some async stuff
    })
  )
  .then((myPromisesAreResolvedArray) => {
    return myMyPromisesAreResolvedArray.filter( // filter ); 
  })

或者,也许正如评论中指出的那样更好,只需将等待的承诺(您修改的数组)的结果存储在 const 中,然后继续您的代码...

  const myPromisesAreResolvedArray = await Promise.all(myArray
    .filter( (e) => {
      // do stuff
    })
    .map( async (e) => { 
      // do some async stuff
    })
  )

  return myPromisesAreResolvedArray.filter( ... );