变量填充后才解决承诺?

时间:2017-03-05 09:26:50

标签: node.js promise

从下面的代码我试图解决这个承诺,只有在游戏对象从api循环中填充数据之后才有意义但是它仍然显示为空:

{
    info: summoner,
    matchIds: {                               << used for loop below
        0: matchIds['matches'][0].matchId,
        1: matchIds['matches'][1].matchId,
        2: matchIds['matches'][2].matchId,
        3: matchIds['matches'][3].matchId,
        4: matchIds['matches'][4].matchId,
        5: matchIds['matches'][5].matchId,
        6: matchIds['matches'][6].matchId,
        7: matchIds['matches'][7].matchId,
        8: matchIds['matches'][8].matchId,
        9: matchIds['matches'][9].matchId
    }
}

var getMatches = function(summoner) {
    var promise = new Promise(function(resolve, reject){
        var opt = {};
        var games = {};                         << object needs to be filled
        for (var val in Object.keys(summoner['matchIds'])) {
            var match = summoner['matchIds'][val];
            opt.id = match;
            api.getMatchById(opt, function(err, game) {
                games[x] = game;
            })
        }
        console.log(games);
        resolve({games});
    });
    return promise;
};

2 个答案:

答案 0 :(得分:1)

您的代码假设api.getMatchById()是同步的,但可能不是,因此for循环在您的任何api.getMatchById()调用完成之前就已完成,因此当您进行游戏时,游戏始终为空解决。您必须跟踪所有api.getMatchById()次呼叫的完成时间,并且只有在发生这种情况时才会解决。

对此进行编码的最佳方式是宣传api.getMatchById(),然后使用Promise.all()跟踪他们何时完成。如果您不打算这样做,那么您可以创建一个手动计数器:

var getMatches = function(summoner) {
    return new Promise(function(resolve, reject){
        var cntr = 0;
        var opt = {};
        var games = {};
        var keys = Object.keys(summoner['matchIds']);
        keys.forEach(function(key) {
            var match = summoner['matchIds'][key];
            opt.id = match;
            api.getMatchById(opt, function(err, game) {
                // need some error handling here
                games[x] = game;
                ++cntr;
                // when all api calls are done, resolve
                if (cntr === keys.length) {
                    resolve({games});
                }
            })
        });
    });
};

另外,请不要使用for / in来迭代数组的项目,因为它可能容易出问题。在ES6中,您可以使用for / of。我在这里使用.forEach()

答案 1 :(得分:0)

如果使用可能的解决方案,不是纯粹的承诺,而是bluebird

const Promise = require('bluebird');
const promise = new Promise(function (resolve, reject) {
  const propsPromise = {};
  Object.keys(summoner['matchIds']).forEach(val => {
    const match = summoner['matchIds'][val];
    propsPromise[match] = new Promise((resolve, reject) => {
        api.getMatchById(opt, (err, game) => {
            if (err) {
                return reject(err);
            }
            resolve(game);
        });
    });});
    return Promise.props(propsPromise);
});

只要对象将通过内容解析,您的承诺就会得到解决。

文档链接 - Promise.props