【问题标题】:How can I wrap several bluebird promises in a promise?如何在一个 Promise 中包装几个 bluebird Promise?
【发布时间】:2014-04-29 21:29:43
【问题描述】:

我需要一个异步包装器,用于由 db 查询备份的 redis 查询。如果redis查询失败,我想做db查询。如果db查询成功,我想在返回之前将返回的数据添加到redis中。我需要该函数(希望是对象上的几个此类方法之一)来返回一个承诺,因为它将从 node.js 中调用。 我正在使用蓝鸟承诺库,并使用它来承诺 redis。我正在为数据库使用 mongo-gyro,它也是基于蓝鸟的。这两个都独立工作。

非常感谢任何帮助 - 甚至是伪代码 - 尤其是。错误处理

function get_something(key){
redis.get(key).done(function (res){
  if (null !== res){
    return res;  // how do I return a promise here?
  }
})
.done(function (res){
  db.find({'_id:key'}).done(function (res){
    if (null !== res){
      redis.set(key,result)  // set db value in redis
      .then(function(){
           return res;      //how do I return a promise here?
      })
    .catch()...?
    return res;  // how do I return a promise here?
    }
})
.catch...?

};

更新:下面的函数可以正常工作,最后会显示来自 redis 或 mongo 的数据。但是 - 到目前为止,我一直未能成功地将其转换为类上的方法,该方法返回要返回给 node.js 处理程序的承诺。注意 - 我需要添加“绑定”以捕获数据源

var oid = '+++++ test oid ++++++'
var odata = {
    'story': 'once upon a time'
}
var rkey = 'objects:'+ oid
redis.getAsync(rkey).bind(this).then(function(res){ 
  if(res === null){
    this.from = 'db'                            // we got from db
    return db.findOne('objects',{'_id':oid}) 
  }  
  data = JSON.parse(res)
  this.from = 'redis'                           // we got from redis
  return data
})
.then(function(res){    
  if(res !== null && this.from == 'db'){
    data = JSON.stringify(res)
    redis.setAsync(rkey,data)
  } 
  return res
})
.then(function(res){                           // at this point, res is not a promise
  console.log('result from ' + this.from)  
  console.log(res)                              
});

【问题讨论】:

    标签: javascript redis promise bluebird


    【解决方案1】:

    .done 终止承诺链。一般来说,Bluebird 足够聪明,可以自行处理未处理的拒绝。

    你要找的是.then

    redis.get(key).then(function(res){ res is redis .get response
         if(res === null) throw new Error("Invalid Result for key");
         return db.find({"_id":key); // had SyntaxError here, so guessing you meant this 
    }).then(function(res){ // res is redis .find response
         return redis.set(key,result);
    }).catch(function(k){ k.message === "Invalid Result for key",function(err){
       // handle no key found
    });
    

    【讨论】:

    • 嗨本杰明,你确定这个吗?
    • @Roamer-1888 我不确定何时回答不是 100% 清楚的问题。不过,我也犯了一些错误,你指的是哪一部分?
    • 嗨本杰明 - 这很有帮助,但实际上并没有回答我的具体问题。我现在有了我需要工作的功能,mongo 备份了 redis。我仍然需要弄清楚如何将函数(如您的示例)转换为类上的方法。我会看看我是否可以发布我的工作,部分解决方案
    • Benjamin,最糟糕的部分是 SyntaxError,但即使 redis.set() 失败,也可能返回(承诺)结果。 redis.set() 是一个副业活动。虽然我不是真正的蓝鸟人,但我会自己回答这个问题。
    【解决方案2】:

    Ideotype,根据我对您的原始问题和更新的理解,我相信您可以实现您的目标,而无需标记来跟踪哪个来源产生了所需的数据。

    这样的事情应该可以工作:

    function get_something(oid) {
        var rkey = 'objects:' + oid;
        return redis.getAsync(rkey).then(function(res_r) {
            if (res_r === null) {
                return Promise.cast(db.findOne('objects', {'_id': oid})).then(function(res_db) {
                    redis.setAsync(rkey, res_db).fail(function() {
                        console.error('Failed to save ' + rkey + ' to redis');
                    });
                    return res_db;
                });
            }
            return res_r;
        }).then(function (res) {//res here is the result delivered by either redis.getAsync() or db.find()
            if (res === null) {
                throw ('No value for: ' + rkey);
            }
            return res;
        });
    }
    

    注意事项:

    • 您可能需要使用oidrkey 修复这些行。我的理解有限。
    • 这里的模式不寻常,因为 mongo-gyro 查询是可选的,并且后续的 redis 更新对于整个函数的成功是学术性的。
    • Promise.cast() 包装器可能不是必需的,具体取决于 db.findOne() 返回的内容。
    • 这无疑将受益于对 Bluebird 有更深入了解的人的一次重温。

    【讨论】:

    • 感谢 @Roamer-1888 提供有关 Promise.cast 的提示 - 更多 c/leaner 代码。 'oid' 和 'rkey' 只是我们应用程序中真实键的占位符。
    猜你喜欢
    • 2023-03-31
    • 2014-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-21
    • 2019-09-17
    • 2018-05-06
    相关资源
    最近更新 更多