简体   繁体   中英

Javascript push a promise into an array

I'm trying to create an array of promises and call them with Promise.all .

I'm having trouble with correctly pushing the functions into the array, it seems they are being called instead of inserted and wait for Promise.all() .

function findSpecialAbility(players, gameId, message) {
  return new Promise(function(resolve, reject) {
    let playersWithSpecials = _.reject(players, function(p) {
      return p.role === 'alphaWolf' ||
        p.role === 'betaWolf' ||
        p.role === 'villager' ||
        p.role === 'alchemist' ||
        p.targetId === 0 ||
        p.abilityUsed === true;
    });
    if (playersWithSpecials.length === 0) {
      resolve();
    } else {
      let specialsToUse = [];
      for (let i = 0, j = playersWithSpecials.length; i < j; i++) {
        specialsToUse.push(useSpecialAbility(playersWithSpecials[i], gameId, message, players));
      }
      //Promise.all(specialsToUse).then(r = > console.log(r));
    }
  });
}


// Using promise below because some of the role will have database updates.
function useSpecialAbility(playerData, gameId, message, players) {
  return new Promise(function(resolve, reject) {
    if (playerData.role === 'seer') {
      let getTargetData = _.find(players, {
        id: playerData.targetId
      });
      message.guild.members.get(playerData.id).send(`Your target is a ${getTargetData.role}!`);
      resolve('foo');
    }
  });
}

it seems they are being called instead of inserted and wait for Promise.all()

It seems like you want the code inside the promises to simultaneously run when you call Promise.all .

If that is what you want then wrapping code in the promises is probably not what you want.


Instead you need to wrap the code you want to run later in just a plain ole function. You can add those functions to an array and then call each one in a loop. And by the looks of your code, you probably don't even need to promises.

See the example below:

 // this function returns another function `runnable` and can be called later (synchronously) to get the result function runLater (index) { return function runnable() { console.log(`this code is ran later. from ${index}`); return `from ${index}`; } } console.log('this is run now'); const tasks = []; for (let i = 0; i < 3; i += 1) { tasks.push(runLater(i)); } console.log('this is run'); // use Array.prototype.map to map the array of functions to what they return by invoking each one. const valuesOfTasks = tasks.map(task => task()); console.log({valuesOfTasks}); console.log('this is run after');


You only need promises when you're dealing with async control flow. Delaying execution can be done synchronously, just by wrapping a section of code in a function. When you want to execute that code, just invoke the function.

Edit:

I need to wait for all the useSpecialAbility to be done before moving on with my code. Some of them will write/read from the database, that's why I used promises.

In that case you will have to use Promise.all but you'll still need to wrap those promises in functions with no arguments if you want them to all run at the same time.


The code block of promises is actually ran synchronously (vs running the block when you call .then or Promise.all ) so if you still want the promises run later, you can still just wrap them in functions.

See this example:

 function waitThenSay(milliseconds, message) { return new Promise(resolve => { console.log(`waiting to say: "${message}"...`) setTimeout(() => { // log to console for immediate side-effect console.log(message.toUpperCase() + '!'); // also resolve with the message resolve(message); }, milliseconds); }); } console.log('this is run first'); // tasks is an array of functions that return promises const tasks = []; for (let i = 1; i <= 3; i += 1) { tasks.push(() => waitThenSay(i * 2000, `hello from task ${i}`)); } console.log('this is run second'); // execute the tasks by mapping each function to their invocation const arrayOfPromises = tasks.map(task => task()) // call Promise.all on that array Promise.all(arrayOfPromises).then(result => { console.log({result}); });

Hope this helps!

I would like to add a fairly straightforward async/await approach for pushing promises to an array and using Promise.all on them thereafter.

async (req, res, next) => {
    try{
        const promises = [];
        
        //Conditionally add promises to the promises array

        if(req.user.hobby === "Hockey")
            promises.push(() => Hobby.find({name: "Hockey"}));

        else
            promises.push(() => Hobby.find({}));

        if(req.user.country === "Canada")
            promises.push(() => User.find({country: "Canada"}));
        
        //Execute the promises in Promise.all()            
                
        const docs = await Promise.all(promises.map(promise => promise()));
    
        if(docs.length === 0){
            var err = new Error('No documents found');
            err.status = 404;
            return next(err);
        }        

        if(docs[1])
            console.log(docs[1]); //array of User docs with country field value set to Canada
    
        console.log(docs[0]); //array of all hobbys or only hobbys with the name field set to Hockey

        res.json(docs);
    }
    catch(err){
        return next(err);
    }
}

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