因为项目的原因,我接触到了jQuery deferred 的这个神奇的工具,下面我用几个例子,与大家分享我的感悟。
我们有5个很耗时的函数 分别为fA、fB、fC、fD、fE 我们的需求是fA和fB同时执行,fA和fB都执行完了,就同时执行fC 和fD ,其中fC和fD只要有一个执行完了,就可以执行fE了。
先完成第一步,写5个函数,并加入deferred
1 function fA(){ 2 var dtd = $.Deferred(); 3 console.log('fa Start'); 4 setTimeout(function(){ 5 console.log('fa End'); 6 dtd.resolve(); 7 }, 2000); 8 return dtd.promise(); 9 }; 10 11 function fB(){ 12 var dtd = $.Deferred(); 13 console.log('fb Start'); 14 setTimeout(function(){ 15 console.log('fb End'); 16 dtd.resolve(); 17 18 }, 3000); 19 return dtd.promise(); 20 }; 21 22 /*** fC fD fE 省略 ***/
第二步, fA和fB都执行完了,然后XXX
先给出我的做法,我们需要用到$.when()这个函数 ,先看效果
1 $.when(fA(), fB()).done(function(){ 2 console.log('when fA, fB is solved'); 3 });
打开控制台:
1 fa Start 2 fb Start 3 fa End 4 fb End 5 when fA, fB is solved
有个问题: $.when()是什么
$.when() ,给出API文档的地址 http://www.css88.com/jqapi-1.9/jQuery.when/
$.when() 就是接受一个或多个deferred(延迟)对象作为参数, 返回一个deferred(延迟)对象,参数中的deferred对象的状态都变成resolve。就将返回值的状态置为resolve。简单来说,就是坚挺多个deferred回调,都成功,就调用成功的回调(dtd.done())我的理解就是一个deferred的异步‘与门’开关。
延伸一下,我们能自己实现一下$.when()吗? 按照刚刚的分析我试了一下,如下:
1 $.extend({ 2 "myWhen": function(){ 3 var args = arguments; 4 var dtd = $.Deferred(); 5 var argLen = args.length; 6 var solveCount = 0; 7 8 var argSolve = function(){ 9 if(solveCount >= (argLen - 1)){ 10 dtd.resolve(); 11 }else{ 12 solveCount++; 13 } 14 } 15 16 $.each(args, function (i_dtd, v_dtd){ 17 v_dtd.done(argSolve); 18 }); 19 20 return dtd.promise(); 21 } 22 });
调用也改成我们自己的方法:
1 $.myWhen(fA(), fB()).done(function(){ 2 console.log('when fA, fB is solved'); 3 });
打开控制台:
fa Start
fb Start
fa End
fb End
when fA, fB is solved
看来我们的myWhen 成功了。这个只是我们为了学习而造的轮子,下面的例子还是用$.when()
第三步,同时执行fC、fD,只要有一个成功就执行fE。
问题来了,$.when是与门开关,那么有没有或门开关呢?好像jquery还真没准备。不过我们有了上面造轮子的经验,相信应该很容易造一个$.myAtLeast()
1 "myAtLeast": function(){ 2 var args = arguments; 3 var dtd = $.Deferred(); 4 var hasResolve = false; 5 var solve = function(){ 6 if(!hasResolve){ 7 dtd.resolve(); 8 } 9 }; 10 $.each(args, function (i_dtd, v_dtd){ 11 v_dtd.done(solve); 12 }); 13 return dtd.promise(); 14 }
调用一下试试:
1 $.when(fA(), fB()).done(function(){ 2 console.log('when fA, fB has resolved'); 3 $.myAtLeast(fC(), fD()).done(function(){ 4 console.log('fC or fD has resolved'); 5 fE(); 6 }); 7 });
打开控制台:
1 fa Start 2 fb Start 3 fa End 4 fb End 5 when fA, fB has resolved 6 fC Start 7 fD Start 8 fC End 9 fC or fD has resolved 10 fE Start 11 fD End 12 fE End
我们可以清楚的看到,fC End后, fE就执行了,随后fD才结束。
就此,我们实现了,一开始定义的需求。
写的仓促,望大家指出文章中不对的地方。谢谢!