jQuery(五): Deferred

jQuery(五): Deferred

有啥用

一般來講,js請求數據,不管是異步仍是同步,都不會當即獲取到結果,一般而言,咱們通常是是使用回調函數再執行,而 deferred就是解決jQuery的回調函數方案,總的來講,deferred對象就是爲了將某個回調函數延遲到某個時機再執行.html

  1. ajax鏈式寫法:jquery

    //通常寫法:
      $.ajax({
            url: '',
            success: function(){},
            error: function(){},
      })
    
      //deferred
      $.ajax(url)
            .done(function(){}) //至關於success
           .fail(function(){})
  2. 指定同一操做的多個函數,容許添加多個函數
    寫法也很簡單,直接添加在後面就能夠了。ajax

    $.ajax(url)
            .done(function(){})
            .fail(function(){})
            .done(function(){})
  3. 爲多個函數添加指定回調,能夠爲多個不一樣的函數添加同一個回調事件數組

    $.when($.ajax(url),$.ajax(url2))
            .done()
            .fail()
    爲兩個函數執行操做,若是都成功了就執行done中的回調,若是有一個失敗或所有都失敗,就執行fail中的回調
  4. 普通操做的回調
    deferred容許任何操做均可以使用deferred對象的方法,指定回調函數promise

    var wait = function(de){
          var test = function(){
              console.log('開始');
              de.resolve();
            }
        setTimeout(test, 3000);
        return de;
      }
    
      $.when(wait($.Deferred()))
          .done(function(){
                console.log('已完成')
          })
          .fail(function(){
                console.log('失敗')
          })

注意: $.when()的參數只能是deferred對象。異步

咋處理

  1. 關於resolve && rejected
    在上面的時候,會注意到一個resolve,而且會以爲這種鏈式寫法很眼熟,且對promise有一個簡單瞭解的話,大概就知道了。函數

    promise: 一樣也是用於處理異步函數,將異步操做隊列化處理
    
       簡單的promise
       new promise (function(resolve,rejected){
           resolve('成功')
       })
       .then(function(){})
    
       promise.then 接受兩個參數: 
       1、 resolve 表明成功時調用的函數
       2、 rejected 表明失敗時調用的回調
       promise的三個狀態值: pending(初始狀態值), fulfilled(操做成功),rejected(操做失敗)
    $.deferred 一樣也是有三個不一樣的狀態:未完成,已完成,已失敗,當狀態處於已完成(resolve)下回自動調用done()中的回調函數,而resolve()就是人爲將狀態值修改成已完成,同理可證rejected();
    總的來講,核心就是:根據不一樣的狀態值調用回調。
  2. API
    * $.Deferred()
    * $.when()
    * deferred.progress()
    * deferred.promise()
    * deferred.done()
    * deferred.fail()學習

學習下

來看下jQ的源碼是怎麼處理的:this

Deferred: function(func) {
      var tuples = [
        // action, add listener, callbacks,
        // ... .then handlers, argument index, [final state]
        ["notify", "progress", jQuery.Callbacks("memory"),
          jQuery.Callbacks("memory"), 2
        ],
        ["resolve", "done", jQuery.Callbacks("once memory"),
          jQuery.Callbacks("once memory"), 0, "resolved"
        ],
        ["reject", "fail", jQuery.Callbacks("once memory"),
          jQuery.Callbacks("once memory"), 1, "rejected"
        ]
      ],
      state = 'pending',

      // 延遲對象
      deferred = {},
      promise = {
        state: function() {
          return state
        },
        then: function(){},
        promise: function(obj) {
          return obj != null ? jQuery.extend(obj, promise): promise;
        }
      }
      ...
    }

從代碼來看,定一個了數組tuples,以及初始狀態值。tuples存儲了三個狀態下的所需參數,來看下存儲了寫什麼內容:
[狀態, 對應的處理函數, 利用callbacks建立的回調隊列, then方法的回調隊列, index, 最終的狀態值],
咱們能夠看到最終的狀態值只有reject 和resolve纔有。
ok,已經知道deferred的本質是根據不一樣的狀態調用不一樣的方法,而且使用callbacks添加函數,那麼把tuples遍歷一下,生成隊列;
源碼:url

tuples.forEach(function(tuple){
      var list = tuple[2], // 獲取到jQuery.callbacks返回,建立一個隊列
        stateString = tuple[5], //獲取到最終狀態描述
        
        //promise[ progress | done | fail ] = list.add
        promise[tuple[1]] = list.add;
        
       // 若是最終狀態值存在,即處於 reject|| resolve 狀態下;
      if (stateString) {
        list.add(
          function() {
            state = stateString;
          }
          ....
        )
      }
      // 延遲對象狀態 deferred.resolve()
      //deferred[ 'resolve' | reject | notify] = function(){}

      deferred[tuple[0]] = function() {
        deferred[tuple[0]+"Width"](this === deferred ? promise : this, arguments);
        return this;
      }
      
      //jQuery.callbacks.fireWith
      //執行隊列,調用處理函數,綁定執行時的上下文
      deferred[tuple[0] + "With"] = list.fireWith;
    })
    promise.promise(deferred);
    return deferred;

已經遍歷生成了3個隊列,並將三個狀態方法掛載在了延遲對象上。
從代碼中能夠看出,在調用deferred[ reject | resolve]時,實際上是調用了deferred[ rejectWith | resolveWith]方法,本質上是對callbacks.fireWith的調用,以用來執行添加的回調函數,同時設置函數的上下文。
而且能夠看的到,deferred[proress | done | fail] 實際上是copy了callbacks.add方法,將回調函數添加在了執行隊列中。

另外關於對jQuery.deferred對象的詳解,使用,http://www.javashuo.com/article/p-bykzzqzg-ee.html 這篇博文轉載了阮大神的,能夠瞅瞅

相關文章
相關標籤/搜索