I am currently struggling with the control flow of promise (promise newbie!).
I make a call to Redis which returns an array object. I then iterate through each of the results and call back to Redis to get a value and wish to populate these in to a final object out
.
The out object is never populated, im guessing as the forEach has not completed:
(note the Redis client lib returns a when.js based promise as default)
var out = {};
REDISCLIENT.keys("apikey:*")
.then(function (replies) {
replies.forEach(function (key, index) {
REDISCLIENT.get(key)
.then(function (value) {
out[key] = value;
})
.done(console.log(out));
});
})
.catch(console.log)
.done(console.log(out));
How can I guarantee that the forEach loop is complete?
I have read many similar posts (I know this is a duplicate) however have not been able to understand why the inner done() method does not contain the fully complete out
obj.
Im guessing I need to wrap the forEach itself in a promise? Appreciate any direction.
Update 1: huge thanks to @David_Aurelio. I now need to populate out
with the key and values. Here is my attempt:
GLOBAL.REDISCLIENT.keys("apikey:*")
.then(function (replies) {
return when.all(replies.map(function (key, index) {
return GLOBAL.REDISCLIENT.get(key)
.then(function (val) {
out[key] = val;
console.log(key, val);
});
}));
})
.catch(console.log)
.done(function (out) {console.log(out); });
The inner console.log prints the correct key/values
key1 val1
key2 val2
The final done now prints:
[ undefined, undefined ]
It's important to understand that flow control and the data conveyed by a promise chain, are determined by :
when.all()
Here's how to achieve what you want with out
as an inner member.
REDISCLIENT.keys("apikey:*")
.then(function (replies) {
var out = {}: //<<<<< initiate `out` as an inner member
return when.all(replies.map(function (key, index) { //<<<<< here's David Aurelio's when.all(replies.map(...))
return REDISCLIENT.get(key).then(function (value) { //<<<<< `return` here causes `.map()` to build an array of promises.
out[key] = value;
});
})).then(function() { //<<<< here's an additional `.then()` chained to `when.all(...)`
return out; //<<<<< `return` here makes the populated `out` available to the `.done()` callback below.
});
})
.catch(console.log)
.done(function (out_) {
console.log(out_);
});
The ugly outer member has disappeared!
In the .done()
callback, I have changed the member name to out_
in order to emphasize that it is passed as a consequence of that return out
, which happens only when all [geddit] the promises returned by REDISCLIENT.get()
calls have successfully settled.