jquery Deferred

Posted Leo_wlCnBlogs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jquery Deferred相关的知识,希望对你有一定的参考价值。

jquery Deferred使用经验

这周做了个小活动(http://aoqi.100bt.com/zt-2016duanzi/index.html),刚开始时候没看好需求,逻辑都写一块了

最后各种坑要填补,从中也获取了些经验和教训,下面说说这里会用到的$.Deferred;

关于jquery里面的deferred的基本使用方法,阮一峰大婶已经有文章说明了,链接如下:

http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html

这里就说说里面没提及的吧:

页面中逻辑比较麻烦的就是获奖名单的渲染问题,如下图

 

这里需要的逻辑是:

1、获取时间,判断是否有活动过了投票时间,没有则不可点击,页面不渲染

2、过来时间后,判断能否获取到获奖名单,获取到就渲染次阶段的页面,获取不到则渲染前一个阶段的页面,

  前一个阶段的页面还是获取不到则往前回溯,如果到第一个阶段还是没有则页面不渲染。

假设四个页面对应的获奖名单是1.html、2.html、3.html、4.html;

假如此时有时间判断活动时间已经在第四阶段,即是前三个阶段都结束,我们的实现逻辑或许是

复制代码
$.get(\'3.html\').done(function(){
    //渲染页面
}).fail(function (argument) {
    $.get(\'2.html\').done(function (argument) {
        //渲染页面
    }).fail(function (argument) {
        function (argument) {
            $.get(\'1.html\').done(function (argument) {
                // 渲染页面
            }).fail(function (argument) {
                // 不渲染页面
            })
        }
    })
})
复制代码

这是很不可取的,在每个不同的阶段都要嵌套一次,而且每个请求都要等上一个请求发完才发,太慢了。。。

于是就改成类似下面的

复制代码
var linkArr = [\'1.html\',\'2.html\',\'3.html\',\'4.html\']
$nav.each(function(index, el) {
    var $self = $(this);
    $.get(index+\'.html\').done(function (argument) {
         $self.text(\'获奖名单出来了\')
     }).fail(function (argument) {
         $self.addClass(\'graynav\').text(\'敬请期待\');
     });
});
复制代码

能“并行”地发出多个请求,看似不错,然后在添加点击渲染事件,点击不同的nav渲染已经出来的相应获奖名单,嗯,这也是逻辑上需要的

复制代码
$(\'.aCommon_nav\').click(function(event) {
    if($(this).hasClass(\'graynav\')){
        return false;
    }
    var i = $(\'aCommon_nav\').index($(this));
    $.get(linkarr[i], function(data) {
        $inforWrap.html(data)
    });
});
复制代码

这时候,我们只需在“并发”请求结束后调用最后一个可点的nav就完成了。。真赞

可是安装现在这种写法,我们并不能判断是否已经完成了请求,或许需要维护个全局变量num,在每次fail和done再加1,当num等于需要发送的个数之后再调用函数

复制代码
var linkArr = [\'1.html\',\'2.html\',\'3.html\',\'4.html\']
var i = 0;
$nav.each(function(index, el) {
    var $self = $(this);
    if($self.attr(\'xxx\')<=timenum){//由时间判断出的是已经结束的标志
        $.get(index+\'.html\').done(function (argument) {
             i++;
             $self.text(\'获奖名单出来了\');
             if(i==LEN){
                 //DoClickEvent()
             }
         }).fail(function (argument) {
              i++;
             $self.addClass(\'graynav\').text(\'敬请期待\');
              if(i==LEN){
                 //DoClickEvent()
             }
         });
     }
});
复制代码

此时就已经基本完成了此次逻辑了,但是代码实在太糙,需要改进下,下面就用when来完成吧~

复制代码
var linkArr = [\'1.html\',\'2.html\',\'3.html\',\'4.html\'],
    deferredArr = [];
$(\'.aCommon_nav\').each(function(index, el) {
    var $self = $(this);
    if($self.attr(\'xxx\')<=timenum){//由时间判断出的是已经结束的标志
        deferredArr.push($.get(index+\'.html\').done(function (argument) {
             $self.text(\'获奖名单出来了\');
         }).fail(function (argument) {
             $self.addClass(\'graynav\').text(\'敬请期待\');
         }))    
     }
});

$.when.apply(null,deferredArr).always(function(arg){
    $(\'.aCommon_nav:not(.garynav)\').last().click();
})
复制代码

这时候,貌似完成了这个逻辑,but,调试之后发现有时候先执行完done,然后fail然后always然后又done,貌似这顺序有些乱来了。。。

然而我们希望的是先done或者fail最后执行always。

发现原因是绑定顺序导致的,于是发现了两条路走,

第一条,把done和fail逻辑都写在always里面,如下

复制代码
$.when.apply(null,defferredArr).always(function(arg){
    $.each(arguments, function(index, val) {
        val.done(function (argument) {
             $self.text(\'获奖名单出来了\');
         }).fail(function (argument) {
             $self.addClass(\'graynav\').text(\'敬请期待\');
         })
    });
    $(\'.aCommon_nav:not(.garynav)\').last().click();
})
复制代码

这感觉好赞,deferred的回调函数都写一块了,维护起来也开心。

但是当deferredArr里面只有一个元素的时候,发现报错了,好尴尬,只能断点看看,

发现always回调函数里面的arguments竟然是一个数组,第一项是请求返回的数据,第二个是返回状态,第三个是此次请求的deferred对象,

于是我们要加个判断,或加个try.catch包裹着done和fail,代码就不贴了,是在太糊弄了。

 

第二条路,使用setTimeout的黑魔法

复制代码
var linkArr = [\'1.html\',\'2.html\',\'3.html\',\'4.html\'],
    deferredArr = [];
$(\'.aCommon_nav\').each(function(index, el) {
    var $self = $(this);
    if($self.attr(\'xxx\')<=timenum){//由时间判断出的是已经结束的标志
        deferredArr.push($.get(index+\'.html\').done(function (argument) {
             $self.text(\'获奖名单出来了\');
         }).fail(function (argument) {
             $self.addClass(\'graynav\').text(\'敬请期待\');
         }))    
     }
});

$.when.apply(null,deferredArr).always(function(arg){
    setTimeout(function (argument) {
        $(\'.aCommon_nav:not(.garynav)\').last().click();
    },0)
})
复制代码

 

于是这个业务也完成了,废话也讲完了


 

 
 

以上是关于jquery Deferred的主要内容,如果未能解决你的问题,请参考以下文章

jQuery:deferred [转]

jQuery的deferred对象详解

jQuery的deferred对象详解

拥抱基于jquery.deferred的ajax,和层层嵌套回调的ajax说拜拜

什么是deferred对象

javascript异步代码的回调地狱以及JQuery.deferred提供的promise解决方式