`
aijuans
  • 浏览: 1543910 次
社区版块
存档分类
最新评论

jQuery Deferred

 
阅读更多

Deferred是jQuery中对CommonJS的异步模型实现,旨在提供通用的接口,简化异步编程难度。

其是一个可链式操作的对象,提供多个回调函数的注册,以及回调列队的回调,并转达任何异步操作成功或失败的消息。

由于其对jQuery Callbacks的依赖性,如果没有概念的朋友可以查看jQuery Callbacks

 

jQuery.Deferred( [beforeStart ] )

创建一个Deferred对象。

beforeStart:

类型:  FunctionDeferred deferred )
一个在构造函数返回前运行的处理函数。

 

resolve、reject、notify

Defferred中定义了三种动作,resolve(解决)、reject(拒绝)、notify(通知),对应Callbacks对象的fire动作。

进而又提供了可以定义运行时的this对象的fire,即fireWith,所以又有扩展了三个对应的操作resolveWith、rejectWith、notifyWith。

内部对应的事件分别是:done(操作完成)、fail(操作失败)、progress(操作进行中),也就是Callbacks对象的add方法添加监听。

举个简单的例子,我们可以通过deferred.done注册上一个动作完成后的,那么当有地方触发了deferred.resolve或者deferred.resolveWith(这两个方法的差别在于能不能定义回调函数的this对象)时,则回调注册的函数。

其他对应的也是一样的。

代码上大概是这样的:

var dtd = $.Deferred(); // 新建一个deferred对象
var wait = function(dtd){
    var tasks = function(){
        alert("执行完毕!");
        dtd.resolve(); // 改变deferred对象的执行状态
        };
    setTimeout(tasks,5000);
    return dtd;
};

这样我们就有了一个5000ms延迟的wait函数。于是我们就可以这么调用:

wait(dtd).done(function(){ alert("成功了!"); })
               .fail(function(){ alert("出错啦!"); });

 

then

then方法提供了三种事件的注册,只要按顺序作为参数传进去就可以了。

then: function( /* fnDone, fnFail, fnProgress */ ) {
    //分别对应完成后运行的函数,失败后运行的函数,正在运行过程中运行的函数
    var fns = arguments;
    //返回一个新的Deferred的promise,then是上一个Deferred运行后才运行的
    return jQuery.Deferred(function( newDefer ) {
        //分别对不同状态注册函数
        jQuery.each( tuples, function( i, tuple ) {
            var action = tuple[ 0 ],    //取出动作名
            fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];    //取出对应回调函数
            // 分别对当前的Deferred对象注册回调函数,也就是注册deferred[ done | fail | progress ]
            deferred[ tuple[1] ](function() {
                var returned = fn && fn.apply( this, arguments );
                //如果传进来的回调函数会返回Deferred对象则在该对象上注册事件
                if ( returned && jQuery.isFunction( returned.promise ) ) {
                    returned.promise()
                        .done( newDefer.resolve )
                        .fail( newDefer.reject )
                        .progress( newDefer.notify );
                //否则对创建出来的newDefer执行对应事件
                } else {
                    //如果上一个函数有返回值则接受传返回值,否则传上一个Deferred传来的参数
                    newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
                }
            });
        });
        fns = null;
    }).promise();
},

 

Promise

Promise只提供Deferred对象中的thendonefailalwayspipeisResolved, 和isRejected,防止用户自行改变Deferred的状态。

 

完整的Deferred

jQuery.Deferred = function( func ) {
    var tuples = [
            // 动作, 监听事件, 回调函数列队, 最终状态
            [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
            [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
            [ "notify", "progress", jQuery.Callbacks("memory") ]
        ],
        state = "pending",
        //定义promise对象
        promise = {
            //返回当前状态
            state: function() {
                return state;
            },
            //无论成功还是失败都运行回调函数
            always: function() {
                deferred.done( arguments ).fail( arguments );
                return this;
            },
            then: function( /* fnDone, fnFail, fnProgress */ ) {
            //分别对应完成后运行的函数,失败后运行的函数,正在运行过程中运行的函数
                var fns = arguments;
                //返回一个新的Deferred的promise,then是上一个Deferred运行后才运行的
                return jQuery.Deferred(function( newDefer ) {
                    //分别对不同状态注册函数
                    jQuery.each( tuples, function( i, tuple ) {
                        var action = tuple[ 0 ],    //取出动作名
                            fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];    //取出对应回调函数
                        // 分别对当前的Deferred对象注册回调函数,也就是注册deferred[ done | fail | progress ]
                        deferred[ tuple[1] ](function() {
                            var returned = fn && fn.apply( this, arguments );
                            //如果传进来的回调函数会返回Deferred对象则在该对象上注册事件
                            if ( returned && jQuery.isFunction( returned.promise ) ) {
                                returned.promise()
                                    .done( newDefer.resolve )
                                    .fail( newDefer.reject )
                                    .progress( newDefer.notify );
                            //否则对创建出来的newDefer执行对应事件
                            } else {
                                //如果上一个函数有返回值则接受传返回值,否则传上一个Deferred传来的参数
                                newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
                            }
                        });
                    });
                    fns = null;
                }).promise();
            },
            // 如果deferred存在,将promise合并到deferred里,否则返回prmoise
            promise: function( obj ) {
                return obj != null ? jQuery.extend( obj, promise ) : promise;
            }
        },
        deferred = {};
    // 向后兼容
    promise.pipe = promise.then;

    // 对deferred添加剩余的方法
    jQuery.each( tuples, function( i, tuple ) {
        //取出对应列队
        var list = tuple[ 2 ],
            //取出对应状态
            stateString = tuple[ 3 ];
        // 赋予promise[ done | fail | progress ] = list.add
        promise[ tuple[1] ] = list.add;
        // 对状态添加事件处理
        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 ]
        deferred[ tuple[0] ] = function() {
            deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
            return this;
        };
        // 注册有with的方法
        deferred[ tuple[0] + "With" ] = list.fireWith;
    });

    // 将promise中的方法合并到deferred里
    promise.promise( deferred );

    // 如果jQuery.Deferred中的参数存在,则先用这个参数对deferred改造
    if ( func ) {
        func.call( deferred, deferred );
    }

    // 完成
    return deferred;
};

 

jQuery.when

jQuery.when是一个帮助Deferred队列处理的工具,如果传单一Deferred进去,则会返回其promise,如果传多个Deferred进去,则会新建一个Deferred用以管理该Deferred队列。

  • 如果队列中有一个Deferred失败,则整个队列失败。
  • 如果队列中所有Deferred成功,则整个队列成功。
  • 如果队列中所有Deferred开始运行,则整个队列正在运行。 
jQuery.when = function( subordinate /* , ..., subordinateN */ ) {
    var i = 0,
        //将arguments转成数组
        resolveValues = core_slice.call( arguments ),
        //传入Deferred对象总数
        length = resolveValues.length,

        // 未完成的Deferred总数
        remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,

        // Deferred队列管理器,如果参数只有一个Deferred则返回该Deferred
        deferred = remaining === 1 ? subordinate : jQuery.Deferred(),

        // 更新resolve和progress的Deferred数量,全部处在这两个状态则通知管理器
        updateFunc = function( i, contexts, values ) {
            return function( value ) {
                contexts[ i ] = this;
                values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
                if( values === progressValues ) {
                    deferred.notifyWith( contexts, values );
                } else if ( !( --remaining ) ) {
                    deferred.resolveWith( contexts, values );
                }
            };
        },

        progressValues, progressContexts, resolveContexts;

    // 如果传入Deferred总量大于1,则添加事件处理
    if ( length > 1 ) {
        progressValues = new Array( length );
        progressContexts = new Array( length );
        resolveContexts = new Array( length );
        for ( ; i < length; i++ ) {
            //判断参数是不是可用的Deferred
            if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
                resolveValues[ i ].promise()
                    //单个成功则更新成功数
                    .done( updateFunc( i, resolveContexts, resolveValues ) )
                    //单个失败则整个列队失败
                    .fail( deferred.reject )
                    //单个开始运行则更新运行中的个数
                    .progress( updateFunc( i, progressContexts, progressValues ) );
            //不可用则未完成数减1
            } else {
                --remaining;
            }
        }
    }

    // 如果没有任何可用Deferred则直接通知管理器,列队完成
    if ( !remaining ) {
        deferred.resolveWith( resolveContexts, resolveValues );
    }

    //返回Promise
    return deferred.promise();
};

其主要通过内置一个Deferred来管理队列的运行状态,不过其只将Promise暴露在外,而用闭包将所有Deferred保护起来。 

分享到:
评论

相关推荐

    javascript异步处理与Jquery deferred对象用法总结

    本文实例讲述了javascript异步处理与Jquery deferred对象用法。分享给大家供大家参考,具体如下: 这是项目组老大整理的一些关于jquery 异步处理请求,以及使用 jquery deferred 对象的一些常见方法。虽然是项目上...

    jquery Deferred 快速解决异步回调的问题

    jquery Deferred 快速解决异步回调的问题 function ok(name){ var dfd = new $.Deferred(); callback:func(){ return dfd.resolve( response ); } return dfd.promise(); } $.when(ok(1),ok(2)).then(function...

    Deferred:Deferred JS 库 - JQuery Deferred 的替代品

    Deferred.JS 是JQuery Deferred objects的替代品。 (行为与 JQuery Deferred 相同)。 阅读以了解为什么您应该从 JQuery Deferred 迁移到 Deferred.JS。 要从 JQuery Deferred 迁移到 Deferred.JS,请参阅 。 ...

    jQuery通过deferred对象管理ajax异步

    主要介绍了jQuery通过deferred对象管理ajax异步的相关资料,需要的朋友可以参考下

    谈谈jQuery之Deferred源码剖析

    主要介绍了谈谈jQuery之Deferred源码剖析,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    reactive-promise:使 jQuery Deferred 承诺具有React性

    React式承诺使 jQuery.Deferred 承诺具有React性。关于Reactive-Promise 允许您使用承诺作为React数据源。 常见用例包括: 允许 Iron Router 路由等待一个或多个异步任务基于异步任务完成在模板中执行条件渲染使用...

    jQuery Design Patterns(PACKT,2016)

    jQuery is a feature-rich ... Efficiently orchestrate asynchronous procedures using jQuery Deferred and Promises Utilize the most widely-used client-side templating libraries for more complex use cases

    深入解析jQuery中Deferred的deferred.promise()方法

    一个Deferred.Promise对象可以理解为是deferred对象的一个视图,它只包含deferred对象的一组方法,包括:done(),then(),fail(),isResolved(), isRejected(), always(),这些方法只能观察一个deferred的状态,而无法...

    jQuery中deferred对象使用方法详解

    在jquery1.5之后的版本中,加入了一个deferred对象,也就是延迟对象,用来处理未来某一时间点发生的回调函数。同时,还改写了ajax方法,现在的ajax方法返回的是一个deferred对象。 那就来看看deferred对象的用法。 1...

    jQuery Deferred和Promise创建响应式应用程序详细介绍

    接下来我们一起探索一下JavaScript中的 Deferred 和 Promise 的概念Deferred 提供了一个抽象的非阻塞的解决方案(如Ajax 请求的响应),它创建一个promise对象,其目的是在未来某个时间点返回一个响应,感兴趣的可以...

    jQuery之Deferred对象详解

    主要介绍了jQuery之Deferred对象详解,本文深入剖析了jQuery Deferred对象的方法属性等内容,需要的朋友可以参考下

    jQuery.Design.Patterns.178588

    Efficiently orchestrate asynchronous procedures using jQuery Deferred and Promises Utilize the most widely-used client-side templating libraries for more complex use cases About the Author Thodoris ...

    Wrox.Professional.jQuery 2012

    Chapter 13 introduces the jQuery Deferred Object, which was introduced in version 1.5. It is a chainable utility object that provides control over the way callback functions are handled. Chapter 14 ...

    http-jquery:经过测试的jQuery实用http工具功能

    异步GET请求:接受一个url和一个数据参数,并返回一个jQuery Deferred对象。 期望第三方返回JSON。 .getScript() 获取一个URL并返回一个Jqer期望第三方返回一个脚本 .getTemplate() 获取一个URL并返回一个...

    jQuery中借助deferred来请求及判断AJAX加载的实例讲解

    ajax请求异步队列加载 我们在开发程序的时候通常会碰到使用ajax加载数据显示到列表的情况。ajax默认使用异步加载(async:true)。为什么不使用同步呢,因为ajax同步加载会UI渲染线程阻塞的问题。...

    jquery.rest:一个易于使用RESTful API的jQuery插件

    特征简单的使用jQuery Deferred进行异步链接基本身份验证支持有用的错误消息记忆体快取的跨域请求基本用法创建一个客户端。 构造您的API。 提出要求。 首先设置您的页面: &lt;!-- jQuery --&gt;&lt; script src =" ...

    利用jQuery的deferred对象实现异步按顺序加载JS文件

    前段时间看了阮一峰的jQuery的deferred对象详解一文,对jQuery中的deferred的用法了一些了解,今天看到园子里的一篇文章:关于重构JS前端框架的失败经验(顺便怀念那些死去的代码),于是把我之前写的一个利用jQuery...

Global site tag (gtag.js) - Google Analytics