关闭

jquery中的工具方法--Deferred和when

标签: jquery延迟对象
672人阅读 评论(1) 收藏 举报
分类:

在jquery1.5版本以后,Deferred和promise就是jquery中非常常用的两个功能,并且在这个版本利用Deferred又完全重写了ajax模块。Deferred对象是有jquery.Deferred构造的,$.Deferred在jquery代码中,分别在promise方法、Dom ready、ajax模块、动画模块被使用

Deferred的用法

var defer = $.Deferred();
function aaa(){
    console.log("aaa");
    defer.resolve();//完成态 相当于callbacks中的fire
}
aaa();
//相当于callbacks中的add方法 通过done改变状态
defer.done(function(){
    console.log('success');
});

var defer = $.Deferred();
function runAsync(){
    setTimeout(function(){
        console.log('执行完成');
        defer.resolve('data');
    },2000)
    return defer.promise();
}
defer.done(function(data){
    console.log(data);
})
defer.fail(function(data){
    console.log(data);
})
var d = runAsync();
    d.done(function(data){
    console.log(data);
})
d.then(function(data){
    console.log(data);
})

这里需要说明一下deferred和promise的区别,deferred相当于promise的继承类,相比于promise方法,deferred可以通过resolve、reject和 notify改变回调的状态,而promise不能修改回调的状态

$.Deferred的实现

异步队列的方法

添加回调函数方法

  • deferred.done(doneCallbacks[,doneCallbacks]):添加成功回调函数,当异步队列处于成功状态时被调用
  • deferred.fail(failCallbcks[,failCallbacks]): 添加失败回调函数,当异步队列处于失败状态时被触发
  • deferred.progress(progressCallbacks):添加消息回调函数
  • deferred.then(doneCallbacks,failCallbacks[,progressCallbacks]): 添加成功回调函数、失败回调函数、消息回调函数
  • deferred.always(alwaysCallbacks[,alwaysCallbacks]):添加回调函数,当异步队列处于成功或失败状态时调用

执行回调函数方法

  • deferred.resolve(args): 使用指定的参数调用所有的成功回调函数
  • deferred.resolveWith(context[,args]): 使用指定的上下文和参数调用所有的成功回调函数,异步队列进入成功状态
  • deferred.reject(args): 使用指定的参数调用所有失败回调函数,异步队列进入失败状态
  • deferred.rejectWith(context[.args]: 使用指定的上下文和参数调用所有失败回调函数,异步对垒进入失败状态
  • deferred.notify(args): 使用指定的参数调用所有的消息回调函数
  • deferred.notifyWith(context[,args]):使用指定的上下文和参数调用所有的消息回调函数

判断当前状态

  • deferred.state():判断异步队列的当前状态

工具

  • deferred.pipe([doneFilter] [,failFilter] [,progressFilter]): 返回一个新的异步队列的只读副本,通过过滤函数过滤当期那异步队列的状态和值
  • deferred.promise([target]):返回当前Deferred对象的制度副本,或者为普通对象增加异步队列的功能

实现过程

方法jQuery.Deferred(func)创建异步队列的5个关键步骤如下

  1. 创建三个$.Callbacks对象,分别表示函数执行的三个状态,即未完成、完成和失败,并设置初始状态为待定(pending)
  2. 创建异步队列的只读副本promise,其中包含了方法done() 、fail()、progress()、state()、isRejected()、then()、always()、pipe()、promise()
  3. 定义异步队列deferred

    a. 把只读副本promise中的方法添加到异步队列deferred中
    b. 为异步队列deferred添加触发执行成功、失败、消息回调函数的方法,包括resolve()、resolveWith()、reject()、rejectWith()、notify()、notifyWith()
    c. 为异步队列deferred添加设置状态的回调函数

  4. 如果传入函数参数func,则调用。

  5. 返回异步队列deferred

    // 扩展了工具方法Deferred和when
    // $.Deferred();
    // $.when()
    // 延迟对象是基于callbacks对象实现的
    // 实现了对异步的的统一管理
    
    // 提供了always then promise pipe when 等实用的方法 
    jQuery.extend({
    
    Deferred: function( func ) {
        var tuples = [
            // action, add listener, listener list, final state
            // 分别对应完成态 失败态和未完成态
            // resolve相当于callbacks对象中的fire方法 done相当于add方法  resolved为状态
            [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
            [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
            [ "notify", "progress", jQuery.Callbacks("memory") ]
        ],
        state = "pending",
        promise = {
            // 该方法返回当前的状态
            state: function() {
                return state;
            },
            //完成态和失败态都执行该操作
            always: function() {
                deferred.done( arguments ).fail( arguments );
                return this;
            },
            //then方法同时绑定完成态、失败态和未完成态三个回调函数
            then: function( /* fnDone, fnFail, fnProgress */ ) {
                var fns = arguments;
                return jQuery.Deferred(function( newDefer ) {
                    jQuery.each( tuples, function( i, tuple ) {
                        var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
                        // deferred[ done | fail | progress ] for forwarding actions to newDefer
                        // 对各个状态添加回调函数
                        deferred[ tuple[1] ](function() {
                            var returned = fn && fn.apply( this, arguments );
                            //确定回调函数的返回值 
                            if ( returned && jQuery.isFunction( returned.promise ) ) {
                                returned.promise()
                                    .done( newDefer.resolve )
                                    .fail( newDefer.reject )
                                    .progress( newDefer.notify );
                            } else {
                                newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
                            }
                        });
                    });
                    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 = {};
    
    // Keep pipe for back-compat
    promise.pipe = promise.then;
    
    // Add list-specific methods
    // 对映射数组进行遍历操作
    jQuery.each( tuples, function( i, tuple ) {
        var list = tuple[ 2 ],//callback回调
            stateString = tuple[ 3 ];//状态字符串
    
        // promise[ done | fail | progress ] = list.add
        // 对done、fail和progress等同于list.add方法 并将添加回调的方法添加至promise对象中
        promise[ tuple[1] ] = list.add;
    
        // Handle state
        // 只有完成态和失败态有statestring
        if ( stateString ) {
            list.add(function() {
                // state = [ resolved | rejected ]
                state = stateString;
    
            //当完成态的回调被调用时 失败态和进行态就不能被调用
            //i^1为位运算符 当i为1时 结果为0,当i为0时 结果为1
            // [ reject_list | resolve_list ].disable; progress_list.lock
            }, tuples[ i ^ 1 ][ 2 ].disable, 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;
    });
    
    // Make the deferred a promise
    // 将promise和deferred合并
    promise.promise( deferred );
    
    // Call given func if any
    if ( func ) {
        func.call( deferred, deferred );
    }
    
    // All done!
    return deferred;
    },
    

$.when()的用法


$.when方法实现多个回调函数的控制

function aaa(){
    var defer = $.Deferred();
    defer.resolve();
    return defer;
}

function bbb(){
    var defer = $.Deferred();
    defer.resolve();

    return defer;
}
//需求:当两个回调都成功的时候执行操作
//when主要是针对多延迟对象的操作
$.when(aaa(),bbb()).done(function(){
    alert('成功');
}).fail(function(){
    alert('失败');
})

$.when方法中,只有参数中的所有函数都为resolve时,才执行done操作,只要有一个为reject,立即执行fail操作

$.when的实现

  1. 接收若干个对象,参数仅一个且返回值不是Deferred对象将立即执行回调函数
  2. 返回值为Deferred对象和非Deferred对象混杂时,对于非Deferred对象的计数器减一
  3. 当所传参数中所有的Deferred对象都resolve后,执行回调
    // Deferred helper
    when: function( subordinate /* , …, subordinateN */ ) {
    var i = 0,
    resolveValues = slice.call( arguments ),//将arguments变为数组
    length = resolveValues.length,

            // the count of uncompleted subordinates
            // 记录未完成态的回调函数的个数 
            // 当传入的参数为0或传入的参数的返回值不是延迟对象的时候 length为0;
            remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
    
            // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
            // 若只有一个参数,延迟对象即为传入的参数
            // 若没有参数或参数大于1 创建新的延迟对象
            deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
    
        // Update function for both resolve and progress values
        // 更新计数器 
        updateFunc = function( i, contexts, values ) {
            return function( value ) {
                contexts[ i ] = this;
                values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
                if ( values === progressValues ) {
                    deferred.notifyWith( contexts, values );
                    //当计数器减为0时 执行resolve
                } else if ( !(--remaining) ) {
                    deferred.resolveWith( contexts, values );
                }
            };
        },
    
        progressValues, progressContexts, resolveContexts;
    
    // add listeners to Deferred subordinates; treat others as resolved
    if ( length > 1 ) {
        progressValues = new Array( length );
        progressContexts = new Array( length );
        resolveContexts = new Array( length );
        for ( ; i < length; i++ ) {
            if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
                resolveValues[ i ].promise()
                    .done( updateFunc( i, resolveContexts, resolveValues ) )
                    .fail( deferred.reject )//只要有一个失败 触发reject
                    .progress( updateFunc( i, progressContexts, progressValues ) );
            } else {
                //当参数的返回值不是延迟对象 对remaining减1
                --remaining;
            }
        }
    }
    
    // if we're not waiting on anything, resolve the master
    // 针对没有参数或都是完成态的情况
    if ( !remaining ) {
        deferred.resolveWith( resolveContexts, resolveValues );
    }
    
    return deferred.promise();
    }
    });
    
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:96521次
    • 积分:1617
    • 等级:
    • 排名:千里之外
    • 原创:78篇
    • 转载:7篇
    • 译文:0篇
    • 评论:6条
    文章分类