Reputation:
I am so close to finishing the base of this function but i am stuck, and its a little todo with my lack of knowledge in promises and i am learning how they function etc. Regarding my issue, i am looping through some data that is then being stored in an Array that will be passed to another function via promise chain, however the array is being filled with pending promises where i just need the actual data from the promise placed into the array, please see below to understand whats going on:
var getGameData = function(matchIdArray) {
var promise = new Promise(function(resolve,reject) {
console.log('Start getGameData');
s3.headObject({Bucket: 'lolsearchgames', Key: '347341'}, function(err, result) {
console.log('Checking Bucket');
if (err && err.code === 'NotFound') {
console.log('Bucket data Not Found!')
var gameData = new Array();
for (var i = 0; i < matchIdArray.length; i++) {
gameData.push(new Promise(function(res, rej) {
lolapi.Match.get(matchIdArray[i], function (error, gamedata) {
if (error) {
rej(error);
}
if (gamedata) {
console.log('Pushing new data to Array! ' + gamedata.matchId);
res(gamedata);
}
})
}));
}
if (gameData.length === 10) {
console.log(gameData);
resolve(gameData);
}
} else {
console.log('Bucket data Found!');
}
})
});
return promise;
console.log('End getGameData');
};
Upvotes: 0
Views: 939
Reputation: 1
Using Promise.all to wait for all the "gameData" as follows - also use Array#map to avoid having to push to an array
Note: however, that if there's any rejection in any lolapi.Match.get promise, the Promise.all will reject - this may not be what you want, I'm not sure from your code example
var getGameData = function getGameData(matchIdArray) {
var promise = new Promise(function (resolve, reject) {
console.log('Start getGameData');
s3.headObject({ Bucket: 'lolsearchgames', Key: '347341' }, function (err, result) {
console.log('Checking Bucket');
if (err && err.code === 'NotFound') {
console.log('Bucket data Not Found!');
Promise.all(matchIdArray.map(function(matchId) {
return new Promise(function (res, rej) {
lolapi.Match.get(matchId, function (error, gamedata) {
if (error) {
rej(error);
}
res(gamedata);
});
})
}))
.then(resolve)
.catch(reject);
} else {
console.log('Bucket data Found!');
reject('Bucket data Found!');
}
});
});
console.log('End getGameData');
return promise.then(function (results) { // see note below
return results.filter(function (result) {
return result;
});
});
};
Alternative - and I think "tidier" code
var getGameData = function getGameData(matchIdArray) {
return new Promise(function(resolve, reject) {
console.log('Start getGameData');
s3.headObject({
Bucket: 'lolsearchgames',
Key: '347341'
}, function(err, result) {
console.log('Checking Bucket');
if (err && err.code === 'NotFound') {
console.log('Bucket data Not Found!');
resolve();
} else {
console.log('Bucket data Found!');
reject('Bucket data Found!');
}
});
}).then(function() {
return Promise.all(matchIdArray.map(function(matchId) {
return new Promise(function(res, rej) {
lolapi.Match.get(matchId, function(error, gamedata) {
if (error) {
rej(error);
}
res(gamedata);
});
})
}));
}).then(function (results) { // see note below
return results.filter(function (result) {
return result;
});
});
}
If you use Bluebird promises, it has utility methods to "promisify" node callback style functions - in the code below, s3.headObjectAsync
is the promisified version of s3.headObject
and lolapi.Match.getAsync
is the promisified version of lolapi.Match.get
You'll see, using bluebirds promisify, (and ES2015+ arrow notation, since you are using node) makes your code far more compact
var getGameData = function getGameData(matchIdArray) {
return s3.headObjectAsync({
Bucket: 'lolsearchgames',
Key: '347341'
})
// do some gymnastics, because if there's no error, that should reject
// but if the error is "NotFound" that should resolve
.then(results => {
throw {code: 'Bucket data Found!'};
})
.catch(err => {
if (err && err.code === "NotFound") {
return; // this is OK
}
throw err;
})
.then(() => Promise.all(matchIdArray.map(matchId => lolapi.Match.getAsync(matchId))))
.then(results => results.filter(result => result)); // see note below
}
In ES5 code the above is still pretty compact
var getGameData = function getGameData(matchIdArray) {
return s3.headObjectAsync({
Bucket: 'lolsearchgames',
Key: '347341'
}).then(function (results) {
throw { code: 'Bucket data Found!' };
}).catch(function (err) {
if (err && err.code === "NotFound") {
return; // this is OK
}
throw err;
}).then(function () {
return Promise.all(matchIdArray.map(function (matchId) {
return lolapi.Match.getAsync(matchId);
}));
}).then(function (results) { // see note below
return results.filter(function (result) {
return result;
});
});
};
Please note in all these answers, the result would not be exactly what you would expect given your original code. In your original code, if
gamedata
was falsey you just ignored that "Match.get" ... however, you can't do that with Promises - the last .then in the answers filters out the empty results in the promise returned bygetGameData
Upvotes: 2