2017-09-28 11 views
1

Rückruf Ich versuche, meine var todos mit zu füllen, was ich in meinem Redis-Server habe, bekomme ich, dass ich Versprechen verwenden müssen, aber ich bin wahrscheinlich an der richtigen Stelle nicht.Mit Versprechen mit redis

Zuerst bekomme ich alle IDs mit .smembers() Funktion und für jede der ID bekomme ich das Objekt mit der richtigen ID und Parsing es in 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); 
    }); 
}); 

Antwort

1

Das Problem ist, dass Sie ein Versprechen nicht an der richtigen Stelle erstellen. Es muss innerhalb von map Funktion erstellt werden, nicht innerhalb von redis.get Rückruf:

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

Aber viel bessere Lösung ist es, eine promisify Funktion zu erstellen, und alle Callback-Stil Funktionen konvertieren Funktionen promisified:

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)); 
+0

Verändert diese Promisify-Funktion die Ladegeschwindigkeit? Ich bekomme, dass es besser aussieht, aber ich bin immer noch verwirrt, warum ich besser wäre als die vorherige Antwort –

+0

Die Antwort ist ** nein **, _promisify_ Funktion hat keinen Einfluss auf die Leistung. Wie Sie im Beispiel sehen, gibt es ein Objekt mit einfacher Logik zurück: 'reject'-Versprechung, wenn ein Fehler vorliegt, oder' resolve' mit einem asynchronen Aufruf, andernfalls. – alexmac

1

Wenn Sie eine Asynchron-Funktion konvertieren mögen, die einen Rückruf in eine Funktion übernimmt, die ein Versprechen gibt, den allgemeinen Ansatz ist es, die Funktion in einem Versprechen zu wickeln und resolve vom Promise Konstruktor als Callback zur Verfügung gestellt passieren:

function getStuff(cb) { 
 
    setTimeout(() => cb('stuff'), 1000); 
 
} 
 

 
function withPromise() { 
 
    return new Promise(resolve => getStuff(resolve)); 
 
} 
 

 
withPromise().then(console.log);

das bedeutet, dass, anstatt das Versprechen Schöpfung in Ihrem redis Rückruf setzen, sollten Sie es outs bewegen ide davon:

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

Es wäre etwa so aussehen

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