Javascript将承诺推送到数组

时间:2017-11-06 10:21:52

标签: javascript arrays function es6-promise

我正在尝试创建一系列承诺并使用Promise.all调用它们。

我在将函数正确推入数组时遇到问题,似乎是在调用它们而不是插入并等待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');
    }
  });
}

2 个答案:

答案 0 :(得分:5)

  

它们似乎被调用而不是插入并等待Promise.all()

您似乎希望在致电Promise.all时,承诺内的代码同时运行。

如果这就是你想要的,那么在promises中包装代码可能不是你想要的。

相反,你需要在一个普通的ole函数中包装你想要稍后运行的代码。您可以将这些函数添加到数组中,然后在循环中调用每个函数。根据代码的外观,您可能甚至不需要承诺。

请参阅以下示例:

&#13;
&#13;
// 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');
&#13;
&#13;
&#13;

当您处理异步控制流时,您只需要承诺。延迟执行可以同步完成,只需将一段代码包装在一个函数中即可。当您想要执行该代码时,只需调用该函数。

编辑:

  

在继续使用我的代码之前,我需要等待所有useSpecialAbility完成。他们中的一些人会从数据库中写入/读取,这就是我使用承诺的原因。

在这种情况下,您将不得不使用Promise.all,但如果您希望它们全部同时运行,您仍然需要将这些承诺包装在没有参数的函数中。

promises的代码块实际上是同步运行的(当你调用.thenPromise.all时运行块)所以如果你仍然希望稍后运行promises,你仍然可以将它们包装在函数中

见这个例子:

&#13;
&#13;
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});
});
&#13;
&#13;
&#13;

希望这有帮助!

答案 1 :(得分:0)

我想添加一种相当简单的异步/等待方法,用于将promise推送到数组并在其后使用Promise.all。

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