当前位置: 首页 > 工具软件 > jQuery Notify > 使用案例 >

jQuery源码解读-jQuery Deferred对象实现

鄢选
2023-12-01

看jQuery源码Deferred

Deferred: function( func ) {
    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") ]
        ],//定义一个二维数据
        state = "pending",//设置state变量的状态
        promise = {//定义一个promise对象
            state: function() {
                return state;
            },
            always: function() {
                deferred.done( arguments ).fail( arguments );
                return this;
            },
            then: function( /* fnDone, fnFail, fnProgress */ ) {
                var fns = arguments;
                return jQuery.Deferred(function( newDefer ) {
                    jQuery.each( tuples, function( i, tuple ) {
                        var action = tuple[ 0 ],
                            fn = fns[ i ];
                        // deferred[ done | fail | progress ] for forwarding actions to newDefer
                        deferred[ tuple[1] ]( jQuery.isFunction( fn ) ?
                            function() {
                                var returned = fn.apply( this, arguments );//这里是关键,对then里面的函数入参进行回调。
                                if ( returned && jQuery.isFunction( returned.promise ) ) {
                                    returned.promise()
                                        .done( newDefer.resolve )
                                        .fail( newDefer.reject )
                                        .progress( newDefer.notify );
                                } else {
                                    newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
                                }
                            } :
                            newDefer[ action ]
                        );
                    });
                    fns = null;
                }).promise();
            },
            // Get a promise for this deferred
            // If obj is provided, the promise aspect is added to the object
            promise: function( obj ) {
                return obj != null ? jQuery.extend( obj, promise ) : promise;
            }
        },
        deferred = {};//新建一个空对象deferred

    // Keep pipe for back-compat
    promise.pipe = promise.then;

    // Add list-specific methods
    jQuery.each( tuples, function( i, tuple ) {
        var list = tuple[ 2 ],
            stateString = tuple[ 3 ];

        // promise[ done | fail | progress ] = list.add
        promise[ tuple[1] ] = list.add;

        // Handle state
        if ( stateString ) {
            list.add(function() {
                // state = [ resolved | rejected ]
                state = stateString;

            // [ reject_list | resolve_list ].disable; progress_list.lock
            }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
        }

        // deferred[ resolve | reject | notify ] = list.fire
        deferred[ tuple[0] ] = list.fire;
        deferred[ tuple[0] + "With" ] = list.fireWith;
    });

    // Make the deferred a promise
    promise.promise( deferred );

    // Call given func if any
    if ( func ) {
        func.call( deferred, deferred );
    }

    // All done!
    return deferred;
}

短短86行代码,就让延迟对象如此强大,不得不佩服jQuery的鬼斧神工。
javaScript通过回调函数来处理异步请求。而通过回调函数处理异步请求会陷入回调地狱,

function A(callBack){
    callBack();
}

jQuery改变了回调的写法,通过新建一个掩饰对象,把回调函数写在then中,通过改变延迟对象的状态后,再回调then中的回调函数。
then(success回调函数入参,fai回调函数入参)中的函数入参不会立刻执行,而是放入执行任务队列中,等待延迟对象改变状态resolve或者reject。一旦延迟对象改变当前延迟对象的执行状态,立刻调用then(success,fail)中函数入参方法。
按照这个思路,我们简单实现一个链式回调写法的函数。

function $$(){}

$$.prototype.then=function(){
    this.callBack=[].slice.call(arguments);
}
$$.prototype.resolve=function(data){
    var arr=this.callBack;
    for(var i=0;i<arr.length;i++){
        arr[i](data)
    }
};

var a=new $$();
a.then(function b(c){
    console.log("c函数"+c)
},function d(d){
console.log("d函数"+d);
});

a.resolve(2);

输出结果:

c函数2
d函数2

总结:JavaScript处理异步调用,只能通过回调函数来处理异步请求。而jQuery通过语法糖改写了JavaScript通过回调函数调用的写法。通过链式调用.then的形式,把回调函数封装起来,然后通过resolve、reject、notify处理函数调用回调函数。真是巧妙。

 类似资料: