0

I'm running into the following problem.

I have the following promise (simplified):

module.exports.checkVotes = (groupId) =>{
    return new Promise((resolve, reject)=>{
     // some db stuff onoing
     ...
     .then((votes)=>{return resolve(votes}})
     .catch((err)=>{return reject(err}})
    })
}

At some point I'm looping through an object. For each entry i have to call promise above. But before the 2. Promise starts, the first one have to be finished...and so on. I tried this, but as soon as I call the promise it gets executed.

 .then(()=>{
      for (let i=0;i<groups.length;i++){
           // for each group I want to call the promise later
           //but it executes as soon as I push it.
           tasklist.push(this.checkVotes(groups[i])) 
       }

       return tasklist.reduce((promiseChain, currentTask) => {
           return promiseChain.then(chainResults =>
               currentTask.then(currentResult =>
                    [ ...chainResults, currentResult ]
                )
           );
        }, Promise.resolve([])).then(arrayOfResults => {
                console.log(arrayOfResults)
            }).catch((err) =>{console.log(err)});
         })
  })

I can not run this with Promise.all() because for some database things, I need this to run sequentially. Moreover I can not hardcode this because the number of groups is variable.

How can I solve this?

Thanks for helping

mcAngular2
  • 299
  • 1
  • 14
  • Avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it) in `checkVotes`! – Bergi Dec 09 '18 at 13:56
  • Where did you find that `reduce` solution? When using that approach, `taskList` is expected to be an array of promise-returning *functions* ("tasks"), not an array of promises. – Bergi Dec 09 '18 at 13:58
  • What nodejs version do you use? Can you use `async`/`await`? – Bergi Dec 09 '18 at 13:58
  • yes can use asnyc and await – mcAngular2 Dec 09 '18 at 13:59
  • I don't see any problems why you wouldn't use Promise.all as it is right now. Your database requests will start sequentially either way upon checkVotes() invocation. Promise.all is just a nice wrapper to handle all your requests resolution. – Rosmarine Popcorn Dec 09 '18 at 14:11
  • checkVotes internally creates some transactions and I guess blocks some table rows, there I retrieve a pool connections timeout if I'm using Promise.all – mcAngular2 Dec 09 '18 at 14:16

2 Answers2

0

Your problem was with putting promises in the taskList, not tasks (functions that return promises). The idea behind making them run in sequence is to call them in the then callback in the reduce:

return groups.reduce((promiseChain, currentGroup) => {
    return promiseChain.then(chainResults =>
        this.checkVotes(currentGroup).then(currentResult => [...chainResults, currentResult])
//      ^^^^^^^^^^^^^^^
    );
}, Promise.resolve([]))

But if you can use async/await syntax, you don't need to do all of this anyway and can write the much simpler and more efficient

const results = [];
for (const group of groups)
    results.push(await this.checkVotes(group));
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

seems to work like this:

groupIds = [12, 45, 34];
return groupIds .reduce((promise, groupId) => {
                return promise.then(() => {
                    return this.checkVotes(groupId)
                        .then((votes)=>{
                            votesList[groupId] = votes
                        })
                        .catch((err)=>{
                            throw err
                        })
                })
            }, Promise.resolve())
mcAngular2
  • 299
  • 1
  • 14