最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Javascript push a promise into an array - Stack Overflow

programmeradmin0浏览0评论

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');
    }
  });
}

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');
    }
  });
}
Share Improve this question edited Nov 6, 2017 at 10:35 artgb 3,2336 gold badges20 silver badges40 bronze badges asked Nov 6, 2017 at 10:21 TraxTrax 1,5387 gold badges22 silver badges42 bronze badges 4
  • Well.. you're Invoking the function when you try to add it to your array. Hint: as soon as you open that constructor it'll run. – Adrian Commented Nov 6, 2017 at 10:35
  • Yes, I am aware of the issue I just don't know how to get around it... – Trax Commented Nov 6, 2017 at 10:37
  • You can use objects, pass in the function without constructor and execute it in useSpecialAbility. – Adrian Commented Nov 6, 2017 at 10:41
  • Would still have a flow control issue, – Trax Commented Nov 6, 2017 at 10:47
Add a comment  | 

2 Answers 2

Reset to default 12

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);
    }
}
发布评论

评论列表(0)

  1. 暂无评论