javascript - 关于js里promise的自调用疑惑。
高洛峰
高洛峰 2017-04-10 14:24:31
[JavaScript讨论组]

代码场景大致如下。要从redis里获取一个结果集列表,获取的时候先判断是否存在缓存,如果没的话先设置缓存再调用。先贴下函数声明的代码。

exports.totalRank = function () {
    var trDeferred = Q.defer();
    Q.all([
            RedisDB.getDailyRankList(),
            RedisDB.getWeeklyRankList(),
            RedisDB.getMonthlyRankList()
        ]).done(function (result) {
            if(cacheExistsChecker(result)){
                var returnResult = {
                    dailyRank: JSON.parse(result[0])[0].rank,
                    weeklyRank: JSON.parse(result[1])[0].rank,
                    monthlRank:JSON.parse(result[2])[0].rank,
                }
                trDeferred.resolve(returnResult);
            }else{
                CacheAction.setRanksLists().then(function(){
                    RankAction.totalRank().then(function(result){
                        trDeferred.resolve(result);
                    })
                });
            }
        })
    return trDeferred.promise;
}

调用该函数的代码如下:

RankAction.totalRank().then(function(result){
    console.log(result);
}).fail(function(err){
        console.log(err);
    });

调用该方法时候,缓存不存在,所以肯定是进入了else的流程。

现在疑惑就是:

重点关注函数声明那段代码,else里面的RankAction.totalRank().then()里面的trDeferred,该对象是第一次调用就return了的promise对象,还是第一次判断缓存不存在,然后再重新调用totalRank时候重新var的trDeferred?

个人的理解是第一次的trdeferred。因为如果这里不用RankAction.totalRank().then(xxxx),而是直接RankAction.totalRank(),则不返回结果。

求分析解惑一下。

高洛峰
高洛峰

拥有18年软件开发和IT教学经验。曾任多家上市公司技术总监、架构师、项目经理、高级软件工程师等职务。 网络人气名人讲师,...

全部回复(2)
阿神

既然已经用了all,就没必要再构造defer绕一圈了

return all([getA(), getB(), getC()).then(function(result) {
    if(!cacheExistsChecker(result)) { 
        return CacheAction.setRanksLists().then(function() {
            return result;
        });
    )

    return result;
}).then(function(result) {
    return {dailyRank: result..., weekliRank: ....};
});

顺便说说题主代码里的另外几个问题

  • 任何时候,只要构造了一个promise出来,要么return出去让调用者处理,要么自己.done掉把异常搞定。没有被.done掉的promise和 try{ dangerousAction() }catch{ //donothing } 是差不多的概念。调试噩梦
  • 看上去代码里的exports就是RankAction(所以才会有调用自己之类的)。那么为啥缓存不命中的时候要调自己走一下命中的分支呢?结果的话不用额外调用,在自己的scope里面就有result啊
  • 当缓存的CacheAction为啥都没有接收到查询结果result? 无论实际上怎么传值过去 ,这样的耦合都不妙。显式要好于隐式&全局变量是恶魔
  • 最后但其实最重要的问题,如果cacheExistsChecker就是负责检查缓存是否命中的判断,把对应的if语句放在get后面的话,这完全称不上是缓存,无论命中与否都会查redis了啊……缓存读的伪代码一般是return cacheHit() ? cacheGet() : (cacheSet(result = dbGet()), result) 是否hit肯定要最早就判断嘛
巴扎黑

问题好不清晰
调totalrank返回的是trDeferred的promise, 也就是说当你再调该promise的then时,trDeferred把resolve的值也就是你声明里的result传给then

没有什么第一次第二次,你只调一次totalrank当然只有一个trdederred,then跟totalrank又没关系

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号