【问题标题】:Using promise with redis callback将 promise 与 redis 回调一起使用
【发布时间】:2017-09-28 15:16:32
【问题描述】:

我正在尝试用我的 Redis 服务器中的内容填充我的 var todos,我知道我必须使用 Promise,但我可能不在正确的位置。

首先,我使用 .smembers() 函数获取所有 id,对于每个 id,我获取具有正确 id 的对象并将其解析为 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);
    });
});

【问题讨论】:

    标签: node.js asynchronous promise node-redis


    【解决方案1】:

    问题在于您创建的承诺不在正确的位置。它必须在map 函数内部创建,而不是在redis.get 回调内部:

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

    但更好的解决方案是创建一个 promisify 函数,并将所有回调样式的函数转换为 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));
    

    【讨论】:

    • 这个promisify函数会改变加载速度吗?我知道它看起来更好,但我仍然很困惑为什么我会比以前的答案更好
    • 答案是nopromisify函数不影响性能。正如您在示例中看到的,它返回一个逻辑简单的对象:reject promise,当有错误时,或者resolve,否则异步调用的结果。
    【解决方案2】:

    如果要将接受回调的异步函数转换为返回承诺的函数,一般的方法是将函数包装在承诺中,并将Promise构造函数提供的resolve作为回调传递:

    function getStuff(cb) {
      setTimeout(() => cb('stuff'), 1000);
    }
    
    function withPromise() {
      return new Promise(resolve => getStuff(resolve));
    }
    
    withPromise().then(console.log);

    这意味着,与其将 Promise 创建放在 redis 回调中,不如将其移出它:

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

    看起来像

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-07-09
      • 2015-08-17
      • 2020-06-22
      • 2018-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多