简体   繁体   中英

await promise.all chained array-methods

I need to recursively call an API to walk down child entries, and return the filtered results before continuing. I was initially putting the results in an array, and then doing a .forEach , and if I found a match I needed to recurse doing so; however, that didn't work because of the problem described in the answer to this question . So, I tried to modify the answer to that question, but it's still not waiting.

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
  ...
}

So the question is, why is 2 happening before 3 and 4, instead of after them? Shouldn't const databases = await getDatabases(dashboardPage); before 2 be waiting for all the recursive calls that pass through childDatabases = await getDatabases(child.id);after 1?

The direct answer was that I needed to await the Promise.all . Otherwise, the Promise.all is hanging out and waiting for the async/await inside of it, before it gets to the .then , but the parent function just fires off those promises and returns nothing, because no one told it to wait. So, simply,

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

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

It's worth noting that for similar reasons, one can not chain more array methods after an async one. Otherwise, the next chained method will be immediately passed an array... of unresolved promises. So, you can't, for example,

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

Instead, you need to wait for the promises to resolve and then do your additional manipulations, so you put it in a .then :

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM