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
2 Answers
Reset to default 12it 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);
}
}