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

来源:互联网 发布:涂银遮光布有毒吗 知乎 编辑:程序博客网 时间:2024/06/05 01:12

在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-compatpromise.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 anyif ( 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 resolvedif ( 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
原创粉丝点击