jquery异步机制源码分析

来源:互联网 发布:淘宝客为什么要用软件 编辑:程序博客网 时间:2024/06/01 20:51

统揽Deferred全局,如下:

1.  Deferred: function( func ) {            var tuples = [],                state = "pending",                promise = {                    state: function() {},                    always: function() {},                    then: function() {},                    promise: function( obj ) {}                },                deferred = {};            promise.pipe = promise.then;        jQuery.each( tuples, function( i, tuple ) {});        promise.promise( deferred );        if ( func ) {            func.call( deferred, deferred );        }        return deferred;    }
  1. 可以看出,Deferred中有一个promise对象,Deferred最后返回deferred对象,deferred对象刚开始被定义为空对象,那么什么时候为其赋值呢?请看jQuery.each( tuples, function( i, tuple ) {});这一行代码中的内容,其中涉及tuples定义:
    var tuples = [            // action,     add listener,           listener list,       final state            [ "resolve",     "done",   jQuery.Callbacks("once memory"), "resolved" ],            [ "reject",      "fail",   jQuery.Callbacks("once memory"), "rejected" ],            [ "notify",      "progress", jQuery.Callbacks("memory") ]        ];

3.再看jQuery.each( tuples, function( i, tuple ) {});

    jQuery.each( tuples, function( i, tuple ) {            var list = tuple[ 2 ],// jQuery.Callbacks("once memory")                stateString = tuple[ 3 ];            //即将jQuery.Callbacks.add赋值给promise的done | fail | progress回调,至此,promise的方法又多了3个            promise[ tuple[1] ] = list.add;            //若stateString 有值,就向done_list或者failed_list中传入3个回调函数            if ( stateString ) {                list.add(                //第1个回调:将当前状态变为 [ resolved | rejected ],初始状态为pending,若list为done ,就将其状态置为resolved                 function() {                    state = stateString;                },                 //第2个回调:将对应状态中list.add添加的回调disable,若list为done ,就将fail中jQuery.Callbacks("once memory")添加的回调disable                tuples[ i ^ 1 ][ 2 ].disable,                 //第3个回调:锁定当前Callbacks                tuples[ 2 ][ 2 ].lock );            }            // deferred[ resolve | reject | notify ]            deferred[ tuple[0] ] = function() {                deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );                return this;            };            deferred[ tuple[0] + "With" ] = list.fireWith;        });

4.接下来是promise.promise( deferred );这段代码的作用是将 promise中的方法扩展到当前的deferred中,

    promise.promise: function( obj ) {                 return obj != null ? jQuery.extend( obj, promise ) : promise;            }

因此,现在的deferred中的方法有:

    always:()    done:()    fail:()    notify:()    notifyWith:( context, args )    pipe:( /* fnDone, fnFail, fnProgress */ )    progress:()    promise:( obj )    resolve:()    reject:()    rejectWith:resolve:()    resolveWith:( context, args )    state:()    then:( /* fnDone, fnFail, fnProgress */ )    __proto__:Object

这就是最终返回的deferred对象包含的方法。

5.下面分析then方法

    then: function() {                    return jQuery.Deferred(function( newDefer ) {}).promise();                }

先看then方法的骨架,其返回的是当前Deferred中的promise对象,不是deferred对象。then方法递归调用jQuery.Deferred(func ),且通过then方法进入jQuery.Deferred(func )时,func不为空,因此,执行

    if ( func ) {            func.call( deferred, deferred );        }

此时,deferred为从then中进入的jQuery.Deferred(func )返回的deferred对象,相当于下面的newDefer,即进入then方法内部jQuery.Deferred(func )中执行func,即下面的方法:

    var fns = arguments;//then方法的参数, fnDone, fnFail, fnProgress     function( newDefer ) {                    jQuery.each( tuples, function( i, tuple ) {                            var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];//将此处看成fnDone                            // 向deferred[ done | fail | progress ] 中添加对应的回调,此处的deferred是父Deferred中的对象                            deferred[ tuple[1] ](                            //回调函数开始                                    function(){}                            //回调函数结束                                );                    });                        fns = null;                    }

下面分析向父deferred对象中添加的回调函数

function(){            // returned为fnDone|fnFail的返回值,即then的回调函数返回值            var returned = fn && fn.apply( this, arguments );            // 若returned.promise有值,就向returned.promise()返回的当前promise对象的3个回调函数中分别添加父级deferred的3个方法,相当于returned对象在执行resolve时便执行newDefer.resolve,即父级deferred的resolve方法,即用新返回的returned中的resolve方法替换父级deferred的resolve方法            if ( returned && jQuery.isFunction( returned.promise ) ) {                        returned.promise()                        .done( newDefer.resolve )                        .fail( newDefer.reject )                        .progress( newDefer.notify );            } else {            //若returned不是promise对象,则父Deferred立即执行add进来的方法                        newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );                    }

流程分析

  1. 调用resolve时,相当与调用resolveWidth,相当于调用fireWith
  2. fireWith即执行通过done回调函数或者then添加进来的方法,底层用Callbacks.add添加回调,且按照回调的添加顺序执行
  3. 若then中的回调方法返回deferred对象,就用此返回的对象的resolve替换父级deferred中的resolve。
原创粉丝点击