jQuery的Deferred機(jī)制

2018-07-24 10:48 更新

Deferred 對(duì)象是在 jQuery1.5 中引入的回調(diào)管理對(duì)象。其作用,大概就是把一堆函數(shù)按順序放入一個(gè)調(diào)用鏈,然后根據(jù)狀態(tài),來(lái)依次調(diào)用這些函數(shù)。 AJAX 的所有操作都是使用它來(lái)進(jìn)行封裝的。比如我們定義的,當(dāng)請(qǐng)求正常返回時(shí),會(huì)調(diào)用 success 定義的函數(shù),失敗時(shí),會(huì)調(diào)用 error定義的函數(shù)。這里的“失敗”,“正?!本褪菭顟B(tài),而對(duì)應(yīng)的函數(shù),只是調(diào)用鏈中的一個(gè)而且。

先來(lái)看一個(gè)直觀(guān)的例子:

var obj = $.Deferred(function(a){});
obj.done(function(){console.log('1')});
obj.done(function(){console.log('2')});
obj.resolve();

這樣,我們就可以按順序看到 1 , 2 這兩個(gè)輸出了。

總的來(lái)說(shuō), jQuery 的 Deferred 對(duì)象有三個(gè)狀態(tài): done , fail , process 。

  • process 只能先于其它兩個(gè)狀態(tài)先被激發(fā)。
  • done 和 fail 互斥,只能激發(fā)一個(gè)。
  • process 可以被重復(fù)激發(fā),而 done 和 fail 只能激發(fā)一次。

然后, jQuery 提供了一些函數(shù)用于添加回調(diào),激發(fā)狀態(tài)等:

deferred.done()
添加一個(gè)或多個(gè)成功回調(diào)。
deferred.fail()
添加一個(gè)或多個(gè)失敗回調(diào)。
deferred.always()
添加一個(gè)函數(shù),同時(shí)應(yīng)用于成功和失敗。
deferred.progress()
添加一個(gè)函數(shù)用于準(zhǔn)備回調(diào)。
deferred.then()
依次接受三個(gè)函數(shù),分別用于成功,失敗,準(zhǔn)備狀態(tài)。
deferred.reject()
激發(fā)失敗狀態(tài)。
deferred.resolve()
激發(fā)成功狀態(tài)。
deferred.notify()
激發(fā)準(zhǔn)備狀態(tài)。

如果一個(gè) Deferred 已經(jīng)被激發(fā),則新添加的對(duì)應(yīng)的函數(shù)會(huì)被立即執(zhí)行。

除了上面的這些操作函數(shù)之外, jQuery 還提供了一個(gè) jQuery.when() 的回調(diào)管理函數(shù),可以用于方便地管理多個(gè)事件并發(fā)的情況,先看一個(gè) AJAX 的“原始狀態(tài)”例子:

var defer = $.ajax({
  url: '/json.html',
  dataType: 'json'
});

defer.done(function(data){console.log(data)});

.done() 做的事和使用 success 定義是一樣的。

當(dāng)我們需要完成,像“請(qǐng)求A和請(qǐng)求B都完成時(shí),執(zhí)行函數(shù)”之類(lèi)的需求時(shí),使用 $.when() 就可以了:

var defer_1 = $.ajax({
  url: '/json.html',
  dataType: 'json'
});

var defer_2 = $.ajax({
  url: '/jsonp.html',
  dataType: 'jsonp'
});

var new_defer = $.when(defer_1, defer_2);
new_defer.done(function(){console.log('haha')});

在 $.when() 中的 Deferred ,只要有一個(gè)是 fail ,則整體結(jié)果為 fail 。

Deferred 的回調(diào)函數(shù)的執(zhí)行順序與它們的添加順序一致。

這里特別注意一點(diǎn),就是 done / fail / always 與 then 的返回值的區(qū)別。從功能上看,它們都可以添加回調(diào)函數(shù),但是,方法的返回值是不同的。 前組的返回值是原來(lái)的那個(gè) defer 對(duì)象,而 then 返回的是一個(gè)新的 defer 對(duì)象。

then 返回新的 defer 這種形式,可以用于方便地實(shí)現(xiàn)異步函數(shù)的鏈?zhǔn)秸{(diào)用。

比如對(duì)于:

var defer = $.ajax({
    url: '/json',
    dataType: 'json'
});

如果使用 done 方法:

defer.done(function(){
  return $.ajax({
    url: '/json',
    dataType: 'json',
    success: function(){
      console.log('inner')
    }
  });
}).done(function(){
  console.log('here');
});

等同于是調(diào)用了兩次 defer.done , defer.done ,注冊(cè)的兩次回調(diào)函數(shù)依次被執(zhí)行后,我們看到的輸出是:

here
inner

這是兩次 defer.done 的結(jié)果,第一個(gè)回調(diào)函數(shù)返回了一個(gè)新的 defer 沒(méi)任何作用。

如果換成 then 方法的話(huà):

defer.then(function(){
  return $.ajax({
    url: '/json',
    dataType: 'json',
    success: function(){
      console.log('inner')
    }
  });
}).done(function(){
  console.log('here');
});

上面的代碼相當(dāng)于:

var new_defer = defer.then(...);
new_defer.done(...);

它跟兩次 defer.done 是不同的。 new_defer 會(huì)在 inner 那里的 defer 被觸發(fā)時(shí)再被觸發(fā),所以輸出結(jié)果是:

inner
here

更一般地來(lái)說(shuō) then 的行為,就是前面的注冊(cè)函數(shù)的返回值,會(huì)作為后面注冊(cè)函數(shù)的參數(shù)值:

var defer = $.ajax({
  url: '/json',
  dataType: 'json'
});

defer.then(function(res){
  console.log(res);
  return 1;
}).then(function(res){
  console.log(res);
  return 2;
}).then(function(res){
  console.log(res);
});

上面代碼的輸入結(jié)果是:

ajax response
1
2


以上內(nèi)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)