用同步的方式执行jQuery异步动画

      在编写jQuery动画时,通过回调函数进行动画队列的编排,但当回调过多,往往会出现这样的代码:

1 $(".box1").fadeIn(1000,function(){
2    $(".box2").fadeIn(1000,function(){
3       $(".box3").hide(1000,function(){
4           // todo xxx
5        }) 
6     })
7 })

      那么是否可以将这种层次的回调以链式的写法完成呢?

      如:f(fn1).f(fn2).f(fn3)... 表示fn1执行完成后fn2,fn2执行完成后执行fn3,...

      下面逐步介绍实现方式:

1、确定结构:

     为实现链式调用,需要f()的返回值一个包含其本身的对象

function f(n){
   var obj = {};
   obj.f = f;
   return obj;
}

    这样就构造好了链式调用的基本结构。

    尝试加入参数:

function f(n){
   console.log(n);
   var obj = {};
   obj.f = function(m){return f(m);};
   return obj;
}

      与我们预想的结果相同,但如结果所见,f调用()会立即将参数代入执行。现在增加一个需求,希望f().f().f()...仅表示一个序列,真正的执行需要我下达其他命令后才发生。于是我们需要在f()的obj中加入一个函数run(),此函数用来下达执行指令,修改代码如下:

1 function f(n){
2    var obj = {};
3    obj.f = function(m){return f(m);};
4    obj.run = function(){
5        console.log(n)
6    }
7    return obj;
8 }

    可以看到,在我们原先的代码并没有输出结果,而当我们执行run()后会怎样呢?

      可以看到仅输出了第三次结果,这是因为run()并没有保存前两次f()参数的值,我们期望的将三次f()一并执行,实际上仅仅执行了第三次。那么如何解决这个问题呢,换句话说:如何在run()中保存所有之前获得的f()的参数呢?

 

2、保存参数:

    我们知道,函数通过参数获得函数外部变量的值,这里我们就通过这种方式保存f()的所有参数,代码修改如下:

 1 function f(n,fn){
 2     var obj = {};
 3     obj.arr = fn===undefined?[]:[fn];
 4     obj.arr.push(n);
 5     obj.f = function(m){return f(m,n);};
 6     obj.run = function(){
 7         $.each(obj.arr,function(i,fn){
 8             fn();
 9          });
10     }
11     return obj;
12  }

      f()中添加obj.arr数组,用来保存所有传入的参数,而run()统一执行所有传入的参数,f()的第二个参数为上一次传入的参数,这样上一次执行所需的参数就被保存了下来。我们将传入的参数换成函数,用如下代码测试:

    可以看到这正是我们想要的结果。

    再次向后追加,希望输出1 2 3,但实际只输出后两次结果,原因在于f()的第二个参数仅保存了上一次传入的参数,而不是前几次的

   

     f()的第二个参数为数组,用来保存前几次已传入的参数,修改代码如下:

function f(n,ar){ 
   var obj = {};    
   obj.arr = ar===undefined?[]:ar;   
   obj.arr.push(n);    
   obj.f = function(m){return f(m,obj.arr);};     
   obj.run = function(){        
      $.each(obj.arr,function(i,fn){         
         fn();          
      });   
  }    
 return obj; 
}

      再次执行之前的代码,已符合预期。

 

3、执行回调

f(
    function () {
       $(".box1").fadeIn(1000);
    }
  ).f(
     function () {
        $(".box2").fadeIn(1000);
    }
 ).run();

    执行上述代码,我们希望看到的是box1用1秒淡入,这个动画执行完后,box2开始执行1秒淡入,但实际上,这两个动画几乎是同时执行,所以接下来的关键是如何执行回调。修改测试代码如下:

f(
    function (cb1) {
       $(".box1").fadeIn(1000,cb1);
    }
  ).f(
     function (cb2) {
        $(".box2").fadeIn(1000,cb2);
    }
 ).run();

      我们看到,cb1和cb2分别为box1和box2执行动画的回调函数,也就是说,我们希望达到这样的效果:在cb1中,执行box2的动画,在cb2中执行后面的动画(如果有),即:需要在cb中下达执行下一个f()中函数的指令。而run()仅仅是控制f()当前携带函数的执行,修改代码如下:

function f(n,ar){ 
   var obj = {};    
   obj.arr = ar===undefined?[]:ar;   
   obj.arr.push(n);    
   obj.f = function(m){return f(m,obj.arr);};     
   obj.run = function(){        
     var fn = obj.arr.shift();
     if(typeof fn === "function") fn(callback);
   }    
   function callback(){
      obj.run();
   }
   return obj; 
}
f(
    function (cb) {
       $(".box1").fadeIn(1000,cb);
    }
  ).f(
     function (cb) {
        $(".box2").fadeIn(1000,cb);
    }
 ).run();

      再次执行以上代码进行测试,实现box1执行完成后执行box2,目标实现

 

转载于:https://www.cnblogs.com/hyaaon/p/4324153.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值