user4815703
user4815703

Reputation:

Resolve promise only after variable filled?

From the code below i am trying to resolve the promise ONLY after games object has its data filled from the api loop if that makes sense but it keeps displaying empty:

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

Upvotes: 0

Views: 182

Answers (2)

Selvatico
Selvatico

Reputation: 503

Hello possible solution if use, not pure promises but bluebird library

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

You out promise will be solved as soon as the object will be resolved with content.

Link to documentation - Promise.props

Upvotes: 0

jfriend00
jfriend00

Reputation: 708016

Your code is assuming that api.getMatchById() is synchronous, but it likely is not and thus the for loop completed before any of your api.getMatchById() calls complete, thus games is always empty when you resolve. You will have to keep track of when all the api.getMatchById() calls are done and only resolve when that happens.

The best way to code this would be to promisify api.getMatchById() and then use Promise.all() to track when they are all done. If you weren't going to do that, then you could create a manual counter:

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

Also, please don't ever use for/in to iterate the items of an array as it can be prone to problems. In ES6, you can use for/of. I used .forEach() here.

Upvotes: 0

Related Questions