Search code examples
javascriptfirebase-realtime-databasees6-promise

Multiple Promise.all - wait for each (and all) to finish


I am trying to execute multiple Promise.all() in sequence and wait for each Promise.all() to finish before proceeding and then return Promise.resolve().

In essence I want to

  1. first - write data to a temporary location.
  2. wait for temporary write to finish then - move the data into place
  3. wait for data to be moved into place then - clean up temporary data
  4. wait for all of above to finish before resolving

My code lives in a Firebase Realtime database trigger event.

The problem I am experiencing is that the database function finishes too early, before all promises are resolved. Why does the function finish before ALL promises are completed?

  return Promise.all(firstPromises)
  .then((firstResult) => {
    // Proceed move data from firstPromises to another location
    let movePromises = []
    movePromises = movePromises.concat(myFunc.moveStuff({dbRoot, from:`${tmpPath}/1`, to:'one'}))
    movePromises = movePromises.concat(myFunc.moveStuff({dbRoot, from:`${tmpPath}/2`, to:'two'}))
    movePromises = movePromises.concat(myFunc.moveStuff({dbRoot, from:`${tmpPath}/3`, to:'three'}))
    movePromises = movePromises.concat(myFunc.moveStuff({dbRoot, from:`${tmpPath}/4`, to:'four'}))
    return Promise.all(movePromises)
  }) 
  .then((moveResult) => {
    // Result from Promise.all(movePromises)
    // Clean up
    return Promise.all(cleanPromises)
  })
  .then((cleanResult) => {
    // Result from Promise.all(cleanPromises)
    return Promise.resolve(true)
  })
  .catch((err) => {
    console.error('Error', err)
    // Clean up
    cleanPromises.push(myFunc.cleanup({dbRoot, path:tmpPath}))
    return Promise.all(cleanPromises)
    // return Promise.reject(err)
  })

myFunc.moveStuff():

moveStuff : ({dbRoot, from, to}) => {
  console.log(`moveStuff from '${from}' --> '${to}'`)
  let myPromises = []
  dbRoot.child(from).once('value', (snaps)=>{
    console.log(`${from} to move:`, snaps.numChildren())
    snaps.forEach((node)=>{
      const path = `${to}/${node.key}`
      const nodeData = node.val()
      myPromises.push(
        dbRoot.child(path).set(nodeData)
        .then((writeRes)=> {
          return dbRoot.child(from).remove()
        })
        .then((deleteRes)=>{
          return Promise.resolve(true)
        })
        .catch((e)=>{
          console.error('moveStuff error', e)
          return Promise.reject(e)
        })
      )
    })
  })
  return myPromises
}

This is my console logout:

cleanup my/SYSTEM
moveStuff from '/my-tmp/SYSTEM/1' --> 'one'
moveStuff from '/my-tmp/SYSTEM/2' --> 'two'
moveStuff from '/my-tmp/SYSTEM/3' --> 'three'
moveStuff from '/my-tmp/SYSTEM/4' --> 'four'
Function execution took 3473 ms, finished with status: 'ok'
/my-tmp/SYSTEM/1 to move: 9
/my-tmp/SYSTEM/2 to move: 100
/my-tmp/SYSTEM/3 to move: 0
/my-tmp/SYSTEM/4 to move: 22

Kind regards /K


Solution

  • I solved the problem by clarifying the execution process with more console logs and implementation of async/await.

    moveStuff()

    moveStuff : async ({dbRoot, from, to}) => {
      let myPromises = []
      await dbRoot.child(from).once('value', (snaps)=>{
        console.log(`moveStuff from '${from}' --> '${to}'`)
        console.log(`${from} to move:`, snaps.numChildren())
        snaps.forEach((node)=>{
          const path = `${to}/${node.key}`
          const nodeData = node.val()
          myPromises.push(
            dbRoot.child(path).set(nodeData)
            .then((writeRes)=> {
              return dbRoot.child(from).remove()
            })
            .then((deleteRes)=>{
              return Promise.resolve(true)
            })
            .catch((e)=>{
              console.error('moveStuff error', e)
              return Promise.reject(e)
            })
          )
        })
      })
      return myPromises
    }
    

    Promise chain:

      return Promise.all(firstPromises)
      .then((firstResult) => {
        // Proceed move data from firstPromises to another location
        console.log('First finished')
        let movePromises = []
        movePromises = movePromises.concat(await myFunc.moveStuff({dbRoot, from:`${tmpPath}/1`, to:'one'}))
        movePromises = movePromises.concat(await myFunc.moveStuff({dbRoot, from:`${tmpPath}/2`, to:'two'}))
        movePromises = movePromises.concat(await myFunc.moveStuff({dbRoot, from:`${tmpPath}/3`, to:'three'}))
        movePromises = movePromises.concat(await myFunc.moveStuff({dbRoot, from:`${tmpPath}/4`, to:'four'}))
        return Promise.all(movePromises)
      }) 
      .then((moveResult) => {
        // Result from Promise.all(movePromises)
        console.log('Move finished')
        // Clean up
        return Promise.all(cleanPromises)
      })
      .then((cleanResult) => {
        console.log('Clean finished')
        // Result from Promise.all(cleanPromises)
        return Promise.resolve(true)
      })
      .catch((err) => {
        console.error('Error', err)
        // Clean up
        cleanPromises.push(myFunc.cleanup({dbRoot, path:tmpPath}))
        return Promise.all(cleanPromises)
        // return Promise.reject(err)
      })
    

    My logout now shows

    First finished
    Move finished
    Clean finished
    Function execution took 3473 ms, finished with status: 'ok'