jquery 中的 deferred 对象

参考连接

  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 操做的链式写法php

    $.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 方法。采用链式写法之后,代码的可读性大大提升。css

    这里着重强调一下 jqXHR 对象,从 jQuery 1.5 开始, $.ajax() 返回的 jqXHR对象 自己就是 deferred 对象,所以能够像上面代码中那样进行链式调用。html

    从 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() 代替。jquery

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

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

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

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

    请看下面的代码,它用到了一个新的方法 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()指定的回调函数。api

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

  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中文文档