Reputation: 310
I'm trying to populate my var todos
with what I have in my Redis server, I get that I have to use promises but I'm probably not in the right place.
First of all, I get all ids with .smembers()
function and for each of the id I'm getting the object with the correct id and parsing it into todos
.
var todos=[];
res.locals.redis.smembers("todo:20", function(err, reply){ // i.e. SMEMBERS todo:20 returns 0 and 1
var promises=reply.map(function(elem){
res.locals.redis.get("todo:20:"+elem, function(err, reply1){ // i.e. GET todo:20:0
return new Promise(function(resolve, reject){
todos.push(JSON.parse(reply1));
resolve();
});
});
});
Promise.all(promises)
.then(function(){
res.locals.redis.quit();
res.render('todolist.ejs', {todo: todos});
})
.catch(function(reason){
console.log(reason);
});
});
Upvotes: 2
Views: 5286
Reputation: 19617
The problem is that you create a promise not in the correct place. It must be created inside of map
function, not inside of redis.get
callback:
res.locals.redis.smembers("todo:20", function(err, reply) {
var promises = reply.map(function(elem) {
return new Promise(function(resolve, reject) {
res.locals.redis.get("todo:20:" + elem, function(err, reply1) {
let todo = JSON.parse(reply1);
resolve(todo);
});
});
});
Promise
.all(promises)
.then(function(todos) {
res.locals.redis.quit();
res.render('todolist.ejs', { todo: todos });
})
.catch(function(reason){
console.log(reason);
});
});
But much better solution is to create a promisify function, and convert all callback-style functions to promisified functions:
let promisify = (fn, params) {
return new Promise((resolve, reject) => {
fn(params, (err, res) => {
if (err) {
reject(err);
} else {
resolve(res);
}
});
});
};
promisify(res.locals.redis.smembers, 'todo:20')
.then(reply => {
let promises = reply.map(elem => promisify(res.locals.redis.get, "todo:20:" + elem);
return Promise.all(promises);
})
.then(results => {
let todos = results.map(item => JSON.parse(item));
res.locals.redis.quit();
res.render('todolist.ejs', { todo: todos });
})
.catch(err => console.log(err));
Upvotes: 1
Reputation: 35501
If you want to convert an async function that accepts a callback into a function that returns a promise, the general approach is to wrap the function in a promise and pass resolve
provided by the Promise
constructor as the callback:
function getStuff(cb) {
setTimeout(() => cb('stuff'), 1000);
}
function withPromise() {
return new Promise(resolve => getStuff(resolve));
}
withPromise().then(console.log);
This means that, instead of putting the promise creation within your redis callback, you should move it outside of it:
res.locals.redis.get("todo:20:"+elem, function(err, reply1){ // i.e. GET todo:20:0
return new Promise(...); // <-- move this outside of the callback
});
It would look something like
var promises = reply.map(function(elem){
return new Promise(function(resolve, reject){
res.locals.redis.get("todo:20:"+elem, function(err, reply1) {
todos.push(JSON.parse(reply1));
resolve();
});
});
});
Upvotes: 1