Search code examples
javascriptasynchronouspromisees6-promise

Wait until nested promises resolve


I am trying to make a bunch of nested calls to the database and want to do something once the results have all come back. I'm new to promises so forgive me if I'm totally doing this wrong (probably the case)

My code currently is something like this:

getVideos(user).then((videos) => {
  videos.forEach((video) => {
    getImage(video).then(() => {
      getMembers().then((members) => {
        getComments().then((comments) => {
          getKeywords().then((keywords) => {
            getTranscript().then((transcript) => {
              console.log(members, comments, keywords, transcript)
            }
          }
        }
      }
    })
  })
})

This is obviously super inefficient because getMembers(), getComments(), getKeywords(), and getTranscript() dont need to wait for each other and can all be called asynchronously. Also getImage() can be called asynchronously for every video in the loop without waiting.

I'm trying to change the code to bundle up these promises into one big one so once it resolves I can access all the fetched data in one place. This is my attempt but it prints

Promise{...}, Promise{...}, Promise{...}, Promise{...}

instead of the fetched data.

Any idea what I'm doing wrong and how I can properly change all these nested promises into one? Thanks

let members, comments, keywords, transcript

getVideos(user).then((videos) => {
   let promises = []
   videos.forEach((video) => {
      let p = getImage(video).then(() => {
        members = getMembers()
        comments = getComments()
        keywords = getKeywords()
        transcript = getTranscript()
        return Promise.all([members, comments, keywords, transcript])
      })
      promises.push(p)
  })
  return Promise.all(promises)
})
.then(() => {
  console.log(members, comments, keywords, transcript)
})

Solution

  • Try using two Promise.alls instead - one for each video, and one for the members, comments, keywords, and transcript:

    getVideos(user).then((videos) => Promise.all(
      videos.map(video => getImage(video)
        .then(videoResp => Promise.all([
          getMembers(), // do you need to call these functions with `videoResp`?
          getComments(),
          getKeywords(),
          getTranscript(),
        ]))
      )
    ));
    

    The promise chain will then resolve with something like

    [ [
        // video 1
        v1members,
        v1comments,
        v1keywords,
        v1transcript,
      ],
      [
        // video 2
        v2members,
        v2comments,
        v2keywords,
        v2transcript,
      ],
      // ...
    ]