javascriptnode.jspromisepromise.all

how to use Promise.All with forEach loop in js


after reviewing a number of questions around for/foreach loops I am still not able to get an output of a promise.all batch of functions.

The goal is to call each iteration of doSleepNow() synchronously, but wait in the Promise.all until all results are in before continuing with a .then()

in the below simplified code extract output_A should be giving four versions of doSleepNow().myTimeRes, however I get

myFun1 msg:  All array for myFun1 done
promToCall outputs (myTimeRes) :  [
  [ [Function: promToCall] ],
  [ [Function: promToCall] ],
  [ [Function: promToCall] ],
  [ [Function: promToCall] ]
]

what am I missing to have the Promise.all trigger each loop of doSleepNow()

*Note: using sleep fn as functional stub only

const myArr = [
  {"hello":"Bob"},
  {"hello":"Jane"},
  {"hello":"Elvis"},
  {"hello":"Zac"}
]
var myOutPromArr = [];
    
const sleep = (waitTimeInMs) => new Promise(resolve => setTimeout(resolve, waitTimeInMs));
    
async function doSleepNow(waittime, loopnum) {
    return new Promise((resolve, reject) => {
        var now = new Date().toISOString();
        const inTime = "Time Start sleep for " + loopnum + " is : " + now;
        sleep(waittime).then(() => {
            const now = new Date().toISOString();
            const outTime = "Time End sleep for " + loopnum + " is : " + now;
            const myTimeRes = "myTime = " + inTime + " : " + outTime
            console.log("w" + inTime + " : " + outTime)
            resolve(myTimeRes)
        });
    })
}

async function myFun1(waittime) {
    return new Promise((resolve, reject) => {
        const myArrLen = myArr.length
        var arrCount = 0;
        myArr.forEach((value) => {
            arrCount++
            const promToCall = (waittime, arrCount) => new Promise(resolve => doSleepNow(waittime, arrCount))
            myOutPromArr.push([promToCall])
            if (myArrLen === arrCount) {
                resolve("All array for myFun1 done")
            }
        })
    })
}

myFun1(1000).then((status) => {
    console.log("myFun1 msg: ", status)
    sleep(5000).then(() => {
        Promise.all(myOutPromArr).then((values) => {
            console.log("promToCall outputs (myTimeRes) : ", values); // <== output_A
        })
    })
})


Solution

  • Your main issue is that your myOutPromArr function is an array of arrays of functions. What you want is an array of promises.

    Here is a modified version of your code (trying to keep it as similar as possible to the original) which is more correct. I also took the time to simplify some code to use async/await.

    const myArr = [
      {"hello":"Bob"},
      {"hello":"Jane"},
      {"hello":"Elvis"},
      {"hello":"Zac"}
    ]
    
        
    const sleep = (waitTimeInMs) => new Promise(resolve => setTimeout(resolve, waitTimeInMs));
        
    async function doSleepNow(waittime, loopnum) {
      let now = new Date().toISOString();
      const inTime = "Time Start sleep for " + loopnum + " is : " + now;
      await sleep(waittime)
      
      now = new Date().toISOString();
      const outTime = "Time End sleep for " + loopnum + " is : " + now;
      const myTimeRes = "myTime = " + inTime + " : " + outTime
      return myTimeRes;
    }
    
    async function myFun1(waittime) {
      const myArrLen = myArr.length
      var myOutPromArr = [];
      
      myArr.forEach((value, index) => {
        const promise = doSleepNow(waittime, index + 1)
        myOutPromArr.push(promise)
      })
      
      return myOutPromArr;
    }
    
    myFun1(1000).then((promises) => {
        sleep(5000).then(() => {
            Promise.all(promises).then((values) => {
                console.log("promToCall outputs (myTimeRes) : ", values); // <== output_A
            })
        })
    })