Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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');
    }
  });
}
like image 680
Trax Avatar asked Nov 06 '17 10:11

Trax


People also ask

How do I push a Promise to an array?

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.

Can you push an object into an array JavaScript?

To push an object into an array, call the push() method, passing it the object as a parameter. For example, arr. push({name: 'Tom'}) pushes the object into the array. The push method adds one or more elements to the end of the array.

How are promises executed in JavaScript?

Just to review, a promise can be created with the constructor syntax, like this: let promise = new Promise(function(resolve, reject) { // Code to execute }); The constructor function takes a function as an argument. This function is called the executor function .

Can you return from a Promise JavaScript?

Any of the three things can happened: If the value is a promise then promise is returned. If the value has a “then” attached to the promise, then the returned promise will follow that “then” to till the final state. The promise fulfilled with its value will be returned.


1 Answers

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!

like image 89
Rico Kahler Avatar answered Oct 07 '22 03:10

Rico Kahler