参考链接

  1. jQuery API中文文档
  2. jQuery.Deferred
  3. jQuery.when
  4. jQuery的deferred对象详解
  5. jQuery deferred 对象的 promise 方法
  6. jQuery中的Deferred-详解和使用

什么是 deferred 对象?

延迟对象,在jQuery的1.5引入,是通过调用jQuery.Deferred()方法创建一个可链式调用的工具对象。 它可以注册多个回调到回调队列, 调用回调队列,准备代替任何同步或异步函数的成功或失败状态。——jQuery API中文文档
简单说,deferred对象就是jQuery的回调函数解决方案。在英语中,defer的意思是"延迟",所以deferred对象的含义就是"延迟"到未来某个点再执行。它解决了如何处理耗时操作的问题,对那些操作提供了更好的控制,以及统一的编程接口。——阮一峰

deferred 对象的主要功能

  1. ajax 操作的链式写法

    $.ajax("test.html")
       .done(function(){ alert("success"); })
       .fail(function(){ alert("error"); });

    $.ajax() 操作完成后,如果使用的是低于1.5.0版本的jQuery,返回的是XHR对象,无法进行链式操作;如果是高于1.5.0版本,返回的是deferred对象,可以进行链式操作。可以看到,done() 相当于 success 方法,fail() 相当于 error 方法。采用链式写法以后,代码的可读性大大提高。

    这里着重强调一下 jqXHR 对象,从 jQuery 1.5 开始, $.ajax() 返回的 jqXHR对象 本身就是 deferred 对象,因此可以像上面代码中那样进行链式调用。

    从 jQuery 1.5 开始,$.ajax()返回的jqXHR对象 实现了 Promise 接口, 使它拥有了 Promise 的所有属性,方法和行为。(见Deferred object获取更多信息)。为了让回调函数的名字统一,便于在$.ajax()中使用。jqXHR也提供.error() .success()和.complete()方法。这些方法都带有一个参数,该参数是一个函数,此函数在 $.ajax()请求结束时被调用,并且这个函数接收的参数,与调用 $.ajax()函数时的参数是一致。这将允许你在一次请求时,对多个回调函数进行赋值,甚至允许你在请求已经完成后,对回调函数进行赋值(如果该请求已经完成,则回调函数会被立刻调用)。

    注意事项: jqXHR.success(), jqXHR.error(), 和 jqXHR.complete() 回调从 jQuery 1.8开始 被弃用过时,从jQuery 3.0开始被删除,你可以使用 jqXHR.done(), jqXHR.fail(), 和 jqXHR.always() 代替。

  2. 指定同一操作的多个回调函数
    deferred 对象的一大好处,就是它允许你自由添加多个回调函数。还是以上面的代码为例,如果ajax操作成功后,除了原来的回调函数,我还想再运行一个回调函数,怎么办?很简单,直接把它加在后面就行了。

    $.ajax("test.html")
       .done(function(){ alert('success'); })
       .fail(function(){ alert('error'); })
        .done(function(){ alert('第二个回调函数!'); });

    回调函数可以添加任意多个,它们按照添加顺序执行。

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

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

    $.when($.ajax("test1.html"), $.ajax("test2.html"))
       .done(function(){ alert('success'); })
       .fail(function(){ alert('error'); });

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

    $.when() 方法的使用具体 参见文档

  4. 普通操作的回调函数接口
    deferred 对象的最大优点,就是它把这一套回调函数接口,从ajax操作扩展到了所有操作。也就是说,任何一个操作----不管是ajax操作还是本地操作,也不管是异步操作还是同步操作----都可以使用deferred对象的各种方法,指定回调函数。

    我们来看一个具体的例子,为一个很耗时的操作 wait 指定回调函数:

    var wait = function (dtd) {
        var dtd = $.Deferred(); // 在函数内部,新建一个Deferred对象
        var tasks = function () {
            alert('执行完毕!');
            dtd.resolve(); // 改变Deferred对象的执行状态
        };
    
        setTimeout(tasks, 5000);
        return dtd.promise(); // 返回promise对象
    };
    
    $.when(wait())
        .done(function () { alert('success'); })
        .fail(function () { alert('error'); });

    另一种做法是直接将 wait 函数传入 $.Deferred()

    $.Deferred(wait)
       .done(function(){ alert('success'); })
       .fail(function(){ alert('error'); });

    jQuery 规定,$.Deferred() 可以接受一个函数名(注意,是函数名)作为参数,$.Deferred() 所生成的 deferred 对象将作为这个函数的默认参数。

    更具体的信息请参见 阮一峰的文档

deferred 对象的方法

  1. $.Deferred() 生成一个 deferred 对象。
    jQuery.Deferred( [beforeStart ] ) 工厂函数创建一个新的deferred对象。

    描述: 一个工厂函数,这个函数返回一个链式实用对象,用返回对象方法来在回调队列中注册多个回调, 调用回调队列,传递任何同步或异步函数的成功或失败状态。

    beforeStart : 类型 Function( Deferred deferred ),一个构造函数返回之前调用的函数。

    jQuery.Deferred 方法可以传递一个可选的函数, 这个函数在方法返回之前调用,并且会把新的 deferred(延迟)对象作为 this 对象,将其作为第一个参数传递给函数。例如,被调用的函数可以使用 deferred.then() 绑定回调。
  2. deferred.done() 指定操作成功时的回调函数。
  3. deferred.fail() 指定操作失败时的回调函数。
  4. deferred.promise() 没有参数时,返回一个新的 deferred。 对象,该对象的运行状态无法被改变;接受参数时,作用为在参数对象上部署 deferred 接口。
  5. deferred.resolve() 手动改变 deferred 对象的运行状态为"已完成",从而立即触发 done() 方法。

    一个 Deferred(延迟)对象开始于 pending 状态。 任何回调使用 deferred.then(), deferred.always(), deferred.done(), 或者 deferred.fail() 添加到这个对象都是排队等待执行。调用 deferred.resolve() 转换 Deferred(递延)到 resolved(解决)的状态,并立即执行设置中任何的 doneCallbacks。调用 deferred.reject() 转换 Deferred(递延)到 rejected(拒绝)的状态,并立即执行设置中任何的 failCallbacks。一旦对象已经进入了解决或拒绝状态,它处于该状态。回调仍然可以添加到解决或拒绝 Deferred(递延)- 他们会立即执行。

    $.ajax() 返回的 jqXHR 对象 会根据请求返回的结果,自动改变自身的执行状态。但是,对于其他通过 $.Deferred() 方法生成的 deferred 对象,它们的执行状态必须由程序员手动指定,由代码决定在什么时候触发回调函数。

  6. deferred.reject() 这个方法与 deferred.resolve() 正好相反,调用后将 deferred 对象的运行状态变为"已失败",从而立即触发 fail() 方法。
  7. $.when() 为多个操作指定回调函数。
  8. deferred.then() 方法
    有时为了省事,可以把 done()fail() 合在一起写,这就是 then() 方法。

    $.when($.ajax( '/main.php' ))
       .then(successFunc, failureFunc);

    如果 then() 有两个参数,那么第一个参数是 done() 方法的回调函数,第二个参数是 fail() 方法的回调方法。如果 then() 只有一个参数,那么等同于 done()

  9. deferred.always() 方法
    这个方法也是用来指定回调函数的,它的作用是,不管调用的是 deferred.resolve() 还是 deferred.reject(),最后总是执行。

    $.ajax( 'test.html' )
        .always( function() { alert('已执行!');} );

    更多信息请参见 jQuery API中文文档


澄海风
300 声望15 粉丝

前端开发 | 星汉西流夜未央