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

原创 2016年06月06日 14:41:08

在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();
    }
    });
    
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

deferred/when jQuery 1.5版本以后的一些新方法

$.when().done() deferred

js-jQuery中的Callbacks、Deferred和When对象详解(1)

jQuery的Callbacks、Deferred、promise和when对象分析(1)。

js-jQuery中的Callbacks、Deferred和When对象详解(2)

jQuery的Callbacks、Deferred、promise和when对象分析(2),then方法及其设计思路详解。

jQuery deferred 对象的 promise 方法

jQuery deferred 对象的 promise 方法 jQuery 从 1.5 版本引入了 deferred 对象,这是一个基于 CommonJS Promises/A 的设计,为了方便异步...

jQuery异步框架探究2:jQuery.Deferred方法

最后总结一下,第一篇通过"手枪"模型详细解释了jQuery._Deferred函数的内部原理,本篇通过"未来单兵武器系统"模型详细解释jQuery.Deferred函数的内部原理,可以看到增强型异步对...

jQuery异步框架探究1:jQuery._Deferred方法

jQuery异步框架应用于jQuery数据缓存模块、jQuery ajax模块、jQuery事件绑定模块等多个模块,是jQuery的基础功能之一。实际上jQuery实现的异步回调机制可以看做java ...

jQuery-再叙when方法

再叙when方法,逐步详解。

jquery的deferred使用详解

前言 之前在一篇文章中写过一点when方法的使用,最近看到同事的一篇文章,又详细学习了deferred方法的各种使用技巧。特此总结。 简单介绍 deferred对象就是jQuery的回调函数解...

jQuery的deferred对象和promise对象

Promise是一种令代码异步行为更加优雅的抽象,有了它,我们就可以像写同步代码一样去写异步代码。jQuery从1.5版本开始实现了CommonJS Promise/A规范这一重量级方案,不过没有严格...

jQuery的Deferred对象概述

很久以来,JavaScript 开发者们习惯用回调函数的方式来执行一些任务。最常见的例子就是利用 addEventListener() 函数来添加一个回调函数, 用来在指定的事件(如 click 或 ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)