【问题标题】:await promise.all chained array-methods等待 promise.all 链式数组方法
【发布时间】:2023-03-26 01:05:01
【问题描述】:

我需要递归调用 API 来遍历子条目,并在继续之前返回过滤后的结果。我最初将结果放在一个数组中,然后执行.forEach,如果找到匹配项,我需要递归这样做;但是,由于this question 的答案中描述的问题,这不起作用。因此,我尝试修改该问题的答案,但它仍然没有等待。

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(code)吗?因为Promise.all() 本身就是一个Promise,或者Promise.all 返回一个Promise。
  • 啊哈!是的,这是有道理的。所以Promise.all 在里面等待async/await,在它到达.then 之前,但是父函数只是触发了这些承诺并且什么也不返回,因为没有人告诉它等待它们.
  • 是的,没错。现在你可以自己回答你的问题,因为我今天没有太多时间,所以我不会发布答案。写一个答案也比阅读一个答案更能提高你对 async-await 的了解。我会给你a reference to Promise.all
  • 除了缺少await,您的函数还缺少return 语句;变量databaseschildDatabases 的使用很奇怪。 childDatabases 在每次 map 迭代中都会被覆盖,从而丢弃许多递归调用的结果。并且永远不会使用您的承诺数组中的 childDbs 结果值!
  • @Bergi,是的——这两个都是我在修复这个问题之前没有发现的错误:) 我使用 StackOverflow 的程度不足以对礼仪充满信心。如果有意义,我可以返回并编辑帖子,以免出现那些不相关的错误。

标签: javascript node.js async-await es6-promise


【解决方案1】:

直接的答案是我需要awaitPromise.all。否则,Promise.all 会挂出并等待其中的async/await,然后才能到达.then,但父函数只会触发这些承诺并且什么也不返回,因为没有人告诉它等待。所以,简单地说,

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 ); 
  })

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

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

  return myPromisesAreResolvedArray.filter( ... );

【讨论】:

  • "所以你把它放在.then" - 假设你已经使用async/await,更好的选择是使用const promiseResults = await Promise.all(myArray.filter(…).map(…)); return promiseResults.filter(…);跨度>
猜你喜欢
  • 2020-04-28
  • 2020-11-01
  • 2021-03-21
  • 2018-10-27
  • 2020-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多