• jquery1.83 之前所有与异步列队相关的模块的演变回顾


    jQuery在1.5引入了Deferred对象(异步列队),当时它还没有划分为一个模块,放到核心模块中。直到1.52才分割出来。它拥有三个方法:_Deferred, Deferred与when。

    出于变量在不同作用域的共用,jQuery实现异步列队时不使用面向对象方式,它把_Deferred当作一个工厂方法,返回一个不透明的函数列队。之所以说不透明,是因为它的状态与元素都以闭包手段保护起来,只能通过列队对象提供的方法进行操作。这几个方法分别是done(添加函数),resolveWith(指定作用域地执行所有函数),resolve(执行所有函数),isResolved(判定是否已经调用过resolveWith或resolve方法),cancel(中断执行操作)。但_Deferred自始至终都作为一个内部方法,从没有在文档中公开过。

    Deferred在1.5是两个_Deferred的合体,但1+1不等于2,它还是做了增强。偷偷爆料,Deferred本来是python世界大名鼎鼎的Twisted框架的东西,由早期七大JS类库中的MochiKit取经回来,最后被dojo继承衣钵。jQuery之所以这样构造Deferred,分明不愿背抄袭的恶名,于是方法改得一塌糊涂,是jQuery命名最差的API,完全不知所云。它还加入当时正在热烈讨论的promise机制。下面是一个比较列表:

    dojo jQuery 注解
    addBoth then 同时添加正常回调与错误回调
    addCallback done 添加正常回调
    addErrback fail 添加错误回调
    callback done 执行所有正常回调
    errback reject 执行所有错误回调
      doneWith 在指定作用域下执行所有正常回调,但dojo已经在addCallback上指定好了
      rejectWith 在指定作用域下执行所有错误回调,但dojo已经在addErrback上指定好了
      promise 返回一个外界不能改变其状态的Deferred对象(外称为Promise对象)

    jQuery的when方法用于实现回调的回调,或者说,几个异列列队都执行后才执行另外的一些回调。这些后来的回调也是用done, when, fail添加的,但when返回的这个对象已经添加让用户控制它执行的能力了。因为这时它是种叫Promise的东西,只负责添加回调与让用户窥探其状态。一旦前一段回调都触发了,它就自然进入正常回调列队(deferred ,见Deferred方法的定义)或错误回调列队(failDeferred )中去。不过我这样讲,对于没有异步编程经验的人来说,肯定听得云里雾里。看实例好了。

    $.when({aa:1}, {aa:2}).done(function(a,b){
           console.log(a.aa)
            console.log(b.aa)
       });

    直接输出1,2。如果是传入两个函数,也是返回两个函数。因此对于普通的数据类型,前面的when有多少个参数,后面的done, fail方法的回调就有多少个参数。

    function fn(){
         return 4;
     }
     
     function log(s){
       window.console && console.log(s)
     }
     $.when( { num:1 }, 2, '3', fn() ).done(function(o1, o2, o3, o4){
         log(o1.num);
         log(o2);
         log(o3);
         log(o4);
     });

    如果我们想得到各个异步的结果,我们需要用resolve, resolveWith, reject, rejectWith进行传递它们。

    var log = function(msg){
        window.console && console.log(msg)
    }
    function asyncThing1(){
        var dfd = $.Deferred();
        setTimeout(function(){
            log('asyncThing1 seems to be done...');
            dfd.resolve('1111');
        },1000);
        return dfd.promise();
    }
    function asyncThing2(){
        var dfd = $.Deferred();
        setTimeout(function(){
            log('asyncThing2 seems to be done...');
            dfd.resolve('222');
        },1500);
        return dfd.promise();
    }
    function asyncThing3(){
        var dfd = $.Deferred();
        setTimeout(function(){
            log('asyncThing3 seems to be done...');
            dfd.resolve('333');
        },2000);
        return dfd.promise();
    }
     
    /* do it */
    $.when( asyncThing1(), asyncThing2(), asyncThing3() ).done(function(res1, res2, res3){
        log('all done!');
        log(res1 + ', ' + res2 + ', ' + res3);
    })

    异步列队一开始没什么人用(现在也没有什么人用,概念太抽象了,方法名起得太烂了),于是它只能在内部自产自销。首先被染指的是queue。queue模块是1.4为吸引社区的delay插件,特地从data模块中分化的产物,而data则是从event模块化分出来的。jQuery新模块的诞生总是因为用户对已有API的局限制不满而致。最早的queue模块的源码:

    1.6添加了_mark,_unmark,promise。queue是让函数同属一个队伍里面,目的是让动画一个接一个执行。_mark则是让它们各自拥有队伍,并列执行(虽然它们只记录异步列队中已被执行的函数个数)。promise则在这些并发执行的动画执行后才执行另些一些回调(或动画)。

    jQuery.ajax模块也被染指,$.XHR对象,当作HTTPXMLRequest对象的仿造器是由一个Deferred对象与一个_Deferred的对象构成。

    deferred = jQuery.Deferred(),
    completeDeferred = jQuery._Deferred(),
    jqXHR  ={/**/}
    //....
    deferred.promise( jqXHR );
    jqXHR.success = jqXHR.done;
    jqXHR.error = jqXHR.fail;
    jqXHR.complete = completeDeferred.done;

    jQuery1.7,从deferred模块中分化出callback模块,其实就是之前的_Deferred的增强版,添加去重,锁定,return false时中断执行下一个回调,清空等功能。

    这期间有还个小插曲,jQuery团队还想增加一个叫Topic的模块,内置发布者订阅者机制,但这封装太溥了,结果被否决。

    虽然把大量代码移动callbacks,但1.7的Deferred却一点没有没变小,它变得更重型,它由三个函数列队组成了。并且返回的是Promise对象,比原来多出了pipe, state, progress, always方法。ajax那边就变成这样:

    deferred = jQuery.Deferred(),
    completeDeferred = jQuery.Callbacks( "once memory" ),
     
    deferred.promise( jqXHR );
    jqXHR.success = jqXHR.done;
    jqXHR.error = jqXHR.fail;
    jqXHR.complete = completeDeferred.add;

    queue那边也没变多少。

    这时候,钩子机制其实已经在jQuery内部蔓延起来,1.5是css模块的cssHooks,1.6是属性模块的attrHooks, propHooks, boolHooks, nodeHooks,1.7是事件模块的fixHooks, keyHooks, mouseHooks,1.8是queue模块的_queueHooks,由于_queueHooks,queue终于瘦身了。

    同时,动画模块迎来了它第三次大重构,它也有一个钩子Tween.propHooks。它多出两个对象,其中Animation返回一个异步列队,Tween 是用于处理单个样式或属性的变化,相当于之前Fx对象。animate被抽空了,它在1.72可是近百行的规模。jQuery通过钩子机制与分化出一些新的对象,将一些巨型方法重构掉。现在非常长的方法只龟缩在节点模块,回调模块。

    animate: function( prop, speed, easing, callback ) {
        var empty = jQuery.isEmptyObject( prop ),
            optall = jQuery.speed( speed, easing, callback ),
            doAnimation = function() {
                // Operate on a copy of prop so per-property easing won't be lost
                var anim = Animation( this, jQuery.extend( {}, prop ), optall );
     
                // Empty animations resolve immediately
                if ( empty ) {
                    anim.stop( true );
                }
            };
     
        return empty || optall.queue === false ?
            this.each( doAnimation ) :
            this.queue( optall.queue, doAnimation );
    },

    到目前为止,所有异步的东西都被jQuery改造成异步列队的“子类”或叫“变种”更合适些。如domReady, 动画,AJAX,与执行了promise或delay或各种特效方法之后的jQuery对象。于是所有异步的东西在promise的加护下,像同步那样编写异步程序。

     
     
    标签: jQuery
  • 相关阅读:
    连载:面向对象葵花宝典:思想、技巧与实践(2)
    关于虚拟化一些思考——不应该盲目使用
    Zimbra8.x邮件服务器安装及配置
    CodeForces 371D. Vessels
    【建模】UML类关系分析
    公式提取软件mathpix
    ROS多线程编程
    ROS节点的初始化及退出详解(ros::init、SIGINT、ros::ok、ros::NodeHandle
    ROS 日志消息(C++)
    Python 中的 if __name__ == '__main__' 该如何理解
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2767627.html
Copyright © 2020-2023  润新知