jquery的总体架构分析及实现示例详解(3)

开发网站的过程中,我们经常遇到某些耗时很长的javascript操作。其中,既有异步的操作(比如ajax读取服务器数据),也有同步的操作(比如遍历一个大型数组),它们都不是立即能得到结果的。

通常的做法是,为它们指定回调函数(callback)。即事先规定,一旦它们运行结束,应该调用哪些函数。

但是,在回调函数方面,jQuery的功能非常弱。为了改变这一点,jQuery开发团队就设计了deferred对象。

简单说,deferred对象就是jQuery的回调函数解决方案。在英语中,defer的意思是"延迟",所以deferred对象的含义就是"延迟"到未来某个点再执行。

回顾一下jQuery的ajax操作的传统写法:

复制代码 代码如下:


$.ajax({
   url: "test.html",
   success: function(){
     alert("哈哈,成功了!");
   },
   error:function(){
     alert("出错啦!");
   }
 });


在上面的代码中,$.ajax()接受一个对象参数,这个对象包含两个方法:success方法指定操作成功后的回调函数,error方法指定操作失败后的回调函数。

$.ajax()操作完成后,如果使用的是低于1.5.0版本的jQuery,返回的是XHR对象,你没法进行链式操作;如果高于1.5.0版本,返回的是deferred对象,可以进行链式操作。

现在,新的写法是这样的:

复制代码 代码如下:


$.ajax("test.html")
  .done(function(){ alert("哈哈,成功了!"); })
  .fail(function(){ alert("出错啦!"); });


为多个操作指定回调函数

deferred对象的另一大好处,就是它允许你为多个事件指定一个回调函数,这是传统写法做不到的。

请看下面的代码,它用到了一个新的方法$.when():

复制代码 代码如下:


$.when($.ajax("test1.html"), $.ajax("test2.html"))

 .done(function(){ alert("哈哈,成功了!"); })

 .fail(function(){ alert("出错啦!"); });

这段代码的意思是,先执行两个操作$.ajax("test1.html")和$.ajax("test2.html"),如果都成功了,就运行done()指定的回调函数;如果有一个失败或都失败了,就执行fail()指定的回调函数。

jQuery.Deferred( func ) 的实现原理

内部维护了三个回调函数列表:成功回调函数列表、失败回调函数列表、消息回调函数列表,其他方法则围绕这三个列表进行操作和检测。

jQuery.Deferred( func ) 的源码结构:

复制代码 代码如下:


 jQuery.extend({

Deferred: function( func ) {
            // 成功回调函数列表
        var doneList = jQuery.Callbacks( "once memory" ),
            // 失败回调函数列表
            failList = jQuery.Callbacks( "once memory" ),
            // 消息回调函数列表
            progressList = jQuery.Callbacks( "memory" ),
            // 初始状态
            state = "pending",
            // 异步队列的只读副本
            promise = {
                // done, fail, progress
                // state, isResolved, isRejected
                // then, always
                // pipe
                // promise          
            },
            // 异步队列
            deferred = promise.promise({}),
            key;
        // 添加触发成功、失败、消息回调函列表的方法
        for ( key in lists ) {
            deferred[ key ] = lists[ key ].fire;
            deferred[ key + "With" ] = lists[ key ].fireWith;
        }
        // 添加设置状态的回调函数
        deferred.done( function() {
            state = "resolved";
        }, failList.disable, progressList.lock )
        .fail( function() {
            state = "rejected";
        }, doneList.disable, progressList.lock );
        // 如果传入函数参数 func,则执行。
        if ( func ) {
            func.call( deferred, deferred );
        }

// 返回异步队列 deferred
        return deferred;
    },
}

jQuery.when( deferreds )

提供了基于一个或多个对象的状态来执行回调函数的功能,通常是基于具有异步事件的异步队列。

jQuery.when( deferreds ) 的用法

如果传入多个异步队列对象,方法 jQuery.when() 返回一个新的主异步队列对象的只读副本,只读副本将跟踪所传入的异步队列的最终状态。

一旦所有异步队列都变为成功状态,“主“异步队列的成功回调函数被调用;

如果其中一个异步队列变为失败状态,主异步队列的失败回调函数被调用。

复制代码 代码如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wgszfg.html