首頁 > web前端 > js教程 > 主體

jQuery.deferred物件使用詳解_jquery

WBOY
發布: 2016-05-16 15:10:20
原創
1148 人瀏覽過

一、前言
jQuery1.5之前,如果需要多次Ajax操作,我們通常會使用下面的兩種方式:

1).串列呼叫Ajax

$.ajax({ success: function() { 
  $.ajax({ success: function() {
    $.ajax({ //callbacks... 
        }); 
  }); 
});  
登入後複製

這種方式程式碼可讀性差,效率低,晦澀難懂,調試和排錯的複雜度大。

2).並行呼叫Ajax

var promises = []; 
$.ajax({
  success: function() { 
    promises.push('resolved'); 
    check(); 
  } 
}); 
$.ajax({ 
  success: function() { 
    promises.push('resolved'); 
    check();
  } 
}); 
$.ajax({ 
  success: function() { 
    promises.push('resolved'); 
    check(); 
  } 
}); 
var check = function() { //checks for all 3 values in the promises array }
登入後複製

這種方式對於callbacks函數呼叫來說已經很不錯了,並行取得數據,可讀性良好。缺點就是程式碼冗長,可擴充性差,調試和排錯的複雜度高。

jQuery1.5之後,增加了deferred物件。因此可以用下面這種方式實現和上面同樣的需求。

1)Promise

var address = $.ajax({}); 
var tweets = $.ajax({}); 
var facebook = $.ajax({}); 
render_side_bar = function(address, tweets, facebook){ 
  //render sidebar 
}
render_no_side_bar = function () { }
$.when(address, tweets, facebook).then(render_side_bar, render_no_side_bar)
登入後複製

可以看出,程式碼可讀性良好,可擴展性高,並且大大降低了調試和排錯的複雜度。

那麼問題來了,promises和deferred物件究竟是個什麼玩意呢?

二、詳解
2.什麼是deferred物件?
deferred物件即延遲對象,它是jQuery 1.5版本引入的一種回呼函數的解決方案,代表了將要完成的某種操作,並且提供了一些方法,幫助使用者使用。

deferred物件是對Promises介面的實作。 jQuery 1.5版本以及之後所有的Ajax回傳的jqXHR物件就是一個deferred物件。

2.deferred物件的幾大好處
2.1.為同一操作指定多個回呼函數
deferred物件的好處之一,就是它允許你為一個操作添加多個回調函數,這在傳統的ajax中是無法實現的。

$.ajax("test.html")
  .done(function(){ alert("first success callback!");} )
  .fail(function(){ alert("there is an error!"); } )
  .done(function(){ alert("second success callback!");} );
登入後複製

2.2.為多個運算指定同一個回呼函數
deferred物件的好處之二,就是它允許你為多個操作指定同一個回呼函數,這在傳統的ajax中也是無法實現的。

$.when($.ajax({}), $.ajax({}))
  .done(function(){ alert("success!"); })
  .fail(function(){ alert("error!"); });
登入後複製

2.3.非Ajax操作的回呼函數
deferred物件的好處之三,就是它不再拘泥於ajax操作,任意的操作(ajax操作or本地操作/非同步操作or同步操作)都可以使用deferred對象,指定回呼函數。

一個很典型的耗時操作

var dfd = $.Deferred(); // create a deferred object
  var wait = function(dtd){
    var tasks = function(){
      alert("over!");
      dtd.resolve(); // change the state of the deferred object from pending to resolved
    };
    setTimeout(tasks,50000);
    return dtd;
  };
登入後複製
$.when(wait(dtd))
  .done(function(){ alert("success!"); })
  .fail(function(){ alert("error!"); });
登入後複製

2.4.鍊式呼叫
jQuery中傳統的ajax操作是這樣的:

$.ajax({
  url: "",
   success: function(){
    alert("success!");
   },
   error:function(){
    alert("error!");
   }
});
登入後複製

其中success指定ajax操作成功後的回呼函數,error指定ajax操作失敗後的回呼函數。 jQuery1.5版本之前,Ajax操作回傳的是一個XMLHTTPRequest對象,不支援鍊式運算。 1.5版本開始,ajax操作返回的是jqXHR對象,這是一個deferred對象,而deferred對像一個顯著的好處就是可以進行鍊式操作,因為deferred對象的所有方法返回的均是deferred對象。

現在的ajax操作的寫法是:

$.ajax({})
  .done(function(){ alert("success!"); })
  .fail(function(){ alert("fail!"); });
登入後複製

兩種寫法對比可以很明顯的看出來,done()相當於傳統ajax操作的success方法,fail()相當於傳統ajax操作的fail方法。相對於傳統的寫法,程式碼可讀性提高了。

3.deferred物件的方法
3.1基本用法
(1).產生deferred物件

var dfd = $.Deferred(); //create a deferred object
(2).deferred物件的狀態

deferred物件有三種狀態

pending:表示操作處於未完成的狀態,任何deferred(延遲)物件開始於pending狀態。
resolved:表示操作成功。
rejected:表示操作失敗。
state()方法傳回deferred物件的目前狀態。

$.Deferred().state(); // 'pending'
$.Deferred().resolve().state(); // 'resolved'
$.Deferred().reject().state(); // 'rejected'
登入後複製

(3).改變deferred物件的狀態

呼叫deferred.resolve() 或 deferred.resolveWith()轉換Deferred(延遲)到resolved(解決)的狀態,並立即執行設定中任何的doneCallbacks。

var callbackFunc = function(){console.log(arguments[0]);}
var dfd = $.Deferred();
dfd.done(callbackFunc);
dfd.resolve("hello"); //'hello'
登入後複製

呼叫deferred.reject() 或 deferred.rejectWith()轉換Deferred(延遲)到rejected(拒絕)的狀態,並立即執行設定中任何的failCallbacks。

var callbackFunc = function(){console.log(arguments[0]);}
var dfd = $.Deferred();
dfd.fail(callbackFunc);
dfd.reject("fail"); //'fail'
登入後複製

(4).綁定回呼函數

deferred物件狀態改變的時候,會觸發回呼函數。任何回呼使用deferred.then(), deferred.always(), deferred.done()或 deferred.fail()加到這個物件都是排隊等待執行。

pending-->resolved,執行設定中任何的doneCallbacks(done()指定),參數由resolved傳遞給doneCallbacks。
pending-->rejected,執行設定中任何的failCallbacks(fail()指定),參數由resolved傳遞給failCallbacks。
pending-->resolved/rejected,執行always()指定的callbacks,參數由resolved傳遞給callbacks。

var f1 = function(){console.log("done");}, 
   f2 = function(){console.log("fail");}, 
   f3 = function(){console.log("always");};

var dfd = $.Deferred();
dfd.done(f1).fail(f2).always(f3);

//if
dfd.resolve(); //'done' 'always'
//if
dfd.reject(); //'fail' 'always'

登入後複製

如果在状态更改后附件一个callback则会立即执行callback,因此不必担心deferred对象何时被resolved或者rejected,因为无论何时,参数都会正确地传递给callbacks。

var fun1 = function(){console.log(arguments[0]);},
  fun1 = function(){console.log(arguments[0]);};
var dfd = $.Deferred();
dfd.done(fun1);
dfd.resolve("hello"); //'hello'
dfd.done(fun2); //'hello'
登入後複製

3.2.deferred对象的方法
(1)$.Deferred([beforeStart]) -- 创建一个deferred对象,参数类型为Function,是一个在构造函数之前调用的函数。

var func = function(){console.log("start");} 
var dfd = $.Deferred(func); //'start' create a deferred object
登入後複製

(2)deferred.done(doneCallbacks [,doneCallbacks]) -- 当deferred(延迟)对象解决时,调用添加处理程序。

args:接受一个或者多个参数,所有的参数都可以是一个单一的函数或者函数数组,当deferred(延迟)对象解决时,doneCallbacks被调用。回调是依照他们添加的顺序执行的。

var func1 = function(){console.log("1");},
   func2 = function(){console.log("2");},
   func3 = function(){console.log("3");};
var dfd = $.Deferred();
dfd.done([func1,func2],func3,[func2,func1]);
dfd.resolve(); // "1 2 3 2 1"
登入後複製

(3)deferred.fail(failCallbacks [,failCallbacks]) -- 当deferred(延迟)对象拒绝时,调用添加处理程序。

args:接受一个或者多个参数,所有的参数都可以是一个单一的函数或者函数数组,当deferred(延迟)对象拒绝时,failCallbacks被调用。回调是依照他们添加的顺序执行的。

var func1 = function(){console.log("1");},
   func2 = function(){console.log("2");},
   func3 = function(){console.log("3");};
var dfd = $.Deferred();
dfd.fail([func1,func2],func3,[func2,func1]);
dfd.reject(); // "1 2 3 2 1"
登入後複製

(4)deferred.resolve(args) and deferred.resolveWith(context [,args]) -- 解决Deferred(延迟)对象,并根据给定的args参数(resolveWith给定context)调用任何doneCallbacks。

参数:args -- type(object),传递给回调函数(doneCallbacks)的可选的参数,

context -- type(object),Context(上下文)作为this对象传递给完成回调函数(doneCallbacks)。

var func = function(arg){console.log(arg);};
$.Deferred().done(func).resolve("done!"); //'done!'
var func = function(arg1,arg2){console.log(arg1.name + ',' + arg2);};
$.Deferred().done(func).resolve({name:'Lucy'},'How are you!'); // 'Lucy,How are you!'
登入後複製

resolve和resolveWith的区别就等同于fire和fireWith的区别。

var func = function () {
  console.log(this.name + ',' + arguments[0] + ' ' + arguments[1] + ' ' + arguments[2]);
};
$.Deferred().done(func).resolveWith({ name: "Lucy" }, ["How", "are", "you!"]);//'Lucy,How are you!'
登入後複製

(5)deferred.reject(args) and deferred.rejectWith(context [,args]) -- 拒绝Deferred(延迟)对象,并根据给定的args参数(rejectWith给定context)调用任何failCallbacks。

参数:args -- type(object),传递给回调函数(doneCallbacks)的可选的参数,

context -- type(object),Context(上下文)作为this对象传递给完成回调函数(doneCallbacks)。

var func = function(arg){console.log(arg);};
$.Deferred().fail(func).reject("error!"); //'error!'
var func = function(ctx,arg){console.log(ctx.name + ',' + arg);};
$.Deferred().fail(func).reject({name:'Mark'},'What happend!'); // 'Mark,What happend!'
登入後複製

reject和rejectWith的区别就等同于fire和fireWith的区别。

var func = function () {
  console.log(this.name + ',' + arguments[0] + ' ' + arguments[1]);
};
$.Deferred().fail(func).rejectWith({ name: "Mark" }, ["what", "happend!"]); // 'Mark,What happend!'
登入後複製

(6)deferred.promise([target]) -- 返回Deferred(延迟)的Promise(承诺)对象。

参数可选,无参数时返回一个Promise(承诺)对象,Promise(承诺)对象仅会暴露那些需要绑定额外的处理或判断状态的延迟方法(then, done, fail, always,pipe, progress, state,和 promise)时,并不会暴露任何用于改变状态的延迟方法(resolve, reject, notify,resolveWith, rejectWith, 和 notifyWith)。使用Promise(承诺)会阻止其他人破坏你制造的promise。

function asyncEvent() {
   var dfd = jQuery.Deferred();

    // Resolve after a random interval
    setTimeout(function () {
       dfd.resolve("hurray");
    }, Math.floor(400 + Math.random() * 2000));

    // Reject after a random interval
    setTimeout(function () {
       dfd.reject("sorry");
    }, Math.floor(400 + Math.random() * 2000));

    // Show a "working..." message every half-second
    setTimeout(function working() {
       if (dfd.state() === "pending") {
          dfd.notify("working... ");
           setTimeout(working, 500);
        }
     }, 1);

      // Return the Promise so caller can't change the Deferred
      return dfd.promise();
 }

// Attach a done, fail, and progress handler for the asyncEvent
$.when(asyncEvent()).then(
    function (status) {
       alert(status + ", things are going well");
    },
    function (status) {
       alert(status + ", you fail this time");
    },
    function (status) {
       alert(status);
    }
);

登入後複製

有参数时,会将事件绑定到参数上,然后返回该参数对象(返回的实际是一个扩展的Promise(承诺)对象)。

var obj = {
  hello: function (name) {
    alert("Hello " + name);
  }
},
// Create a Deferred
dfd = $.Deferred();

// Set object as a promise
dfd.promise(obj);

// Resolve the deferred
dfd.resolve("John");

// Use the object as a Promise
obj.done(function (name) {
   obj.hello(name); // will alert "Hello John"
}).hello("Karl");

登入後複製

(7)$.when(deferreds) -- 提供一种方法来执行一个或多个对象的回调函数。

参数:type(Deferred),一个或多个延迟对象,或者普通的JavaScript对象。

参数仅传入一个单独的Deferred对象,返回它的Promise对象。

function func() {
  var dfd = $.Deferred();
  setTimeout(function () {
    dfd.resolve("hurry");
  }, 500);
  return dfd.promise();
};

$.when(func()).done(function (arg) {
  alert(arg); /*alert "hurry"*/
});

登入後複製

参数传入一个非Deferred和Promise对象,那么该参数会被当成一个被解决(resolved)的延迟对象,并且绑定到上面的任何doneCallbacks都会被立即执行。

$.when( { name: 123 } ).done(
  function(arg) { alert(arg.name); } /* alerts "123" */
);
登入後複製

无参数,返回一个resolved(解决)状态的Promise对象。

$.when().state(); // "resolved"
登入後複製

参数为多个Deferred对象,该方法根据一个新的“宿主” Deferred(延迟)对象,跟踪所有已通过Deferreds聚集状态,返回一个Promise对象。当所有的延迟对象被解决(resolve)时,“宿主” Deferred(延迟)对象才会解决(resolved)该方法,或者当其中有一个延迟对象被拒绝(rejected)时,“宿主” Deferred(延迟)对象就会reject(拒绝)该方法。

var d1 = $.Deferred();
var d2 = $.Deferred();
 
$.when( d1, d2 ).done(function ( v1, v2 ) {
  console.log( v1 ); // "Fish"
  console.log( v2 ); // "Pizza"
});
 
d1.resolve( "Fish" );
d2.resolve( "Pizza" );
登入後複製

(8)deferred.then(doneFilter [,failFilter] [,progressFilter]) -- 当Deferred(延迟)对象解决,拒绝或仍在进行中时,调用添加处理程序。

参数:

doneFilter -- type(Function),当Deferred(延迟)对象得到解决时被调用的一个函数。
failFilter -- type(Function),当Deferred(延迟)对象拒绝时被调用的一个函数,可选。
progressFilter -- type(Function),当Deferred(延迟)对象生成进度通知时被调用的一个函数,可选。
其实,then方法可以理解成,把done(),fail(),progress()合在一起写。

var filterResolve = function () {
   var dfd = $.Deferred(),
     filtered = dfd.then(function (value) { return value * 2; });
   dfd.resolve(5);
   filtered.done(function (value) { console.log(value); });
};
filterResolve(); //'10'

var defer = $.Deferred(),
   filtered = defer.then(null, function (value) {
     return value * 3;
   });

defer.reject(6);
filtered.fail(function (value) {
   alert("Value is 3*6 = " + value);
});

登入後複製

(9)deferred.always(alwaysCallbacks [,alwaysCallbacks]) -- 当Deferred(延迟)对象解决或拒绝时,执行alwaysCallbacks。

顾名思义,只要Deferred对象的状态发生更改(解决或者拒绝)均会调用alwaysCallbacks。

(10)deferred.state() -- 获取一个Deferred(延迟)对象的当前状态,不接受任何参数。

$.Deferred().state();//"pending"
上面讲述过deferre(延迟)对象的三种状态,这个方法对于debug非常有用,例如,在准备reject一个deferred对象之前,判断它是否处于resolved状态。

(11)deferred.notify(args) and deferred.notifyWith()

(12)deferred.progress()

(13)deferred.pipe()

(14).promise()

(15)deferred.isRejected() 和 deferred.isResolved() -- 从jQuery 1.7开始被弃用,较新版本的jQuery类库中已经被删除,可以使用state()方法代替这两个方法。

(16)deferred.pipe() -- 从jQuery 1.8开始被弃用。

4.什么情况下使用deferred对象和Promises?
上面讲了很多,那么我们究竟在什么情况下使用Deferred对象和Promises对象呢?

(1)复杂的动画

不知道动画什么时候结束,但是又必须在动画结束的时候做一些操作或者是启动其他的动画,这种情况下,如果采用其他的方式,很容易导致代码可读性差,尤其是还夹带着一些其它的操作,比如渲染、表单操作等,现在jQuery会为你的动画操作返回一个Promise,这样这些动画可以进行链式操作。

(2)处理队列

复制代码 代码如下:
window.queue = $.when() $('#list').on('click', function() { window.queue = window.queue.then(function() { //do the thing }) } )

(3)The Wait promise

function wait(ms) { 
  var deferred = $.Deferred(); 
  setTimeout(function(){deferred.resolve()}, ms);
  return deferred.promise(); 
}

wait(1500).then(function () {
    // After 1500ms this will be executed 
});
登入後複製

(4)典型的Ajax操作

$.when($.ajax({}), $.ajax({}))
  .done(function(){ alert("success!"); })
  .fail(function(){ alert("error!"); });
登入後複製

(5)一些耗时的大循环操作

以上就是本文的全部内容,希望对大家的学习有所帮助。

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板