首頁  >  文章  >  web前端  >  深入解析jQuery中Deferred的deferred.promise()方法_jquery

深入解析jQuery中Deferred的deferred.promise()方法_jquery

WBOY
WBOY原創
2016-05-16 15:02:211147瀏覽

deferred.promise() 和 .promise()

這兩個API語法幾乎一樣,但有著很大的差異。 deferred.promise()是Deferred實例的一個方法,他傳回一個Deferred.Promise實例。一個Deferred.Promise物件可以理解為是deferred物件的視圖,它只包含deferred物件的一組方法,包括:done(),then(),fail(),isResolved(), isRejected(), always() ,這些方法只能觀察一個deferred的狀態,而無法改變deferred物件的內在狀態。這非常適合於API的封裝。例如一個deferred物件的持有者可以根據自己的需求控制deferred狀態的狀態(resolved或rejected),但是可以把這個deferred物件的Promise物件回傳給其它的觀察者,觀察者只能觀察狀態的變化綁定對應的回呼函數,但是無法更改deferred物件的內在狀態,從而起到很好的隔離保護作用。

deferred.promise()

$(function(){ 
  // 
  var deferred = $.Deferred(); 
  var promise = deferred.promise(); 
   
  var doSomething = function(promise) { 
    promise.done(function(){ 
      alert('deferred resolved.'); 
    }); 
  }; 
   
  deferred.resolve(); 
  doSomething(promise); 
}) 

deferred.promise()也可以接受一個object參數,此時傳入的object將被賦予Promise的方法,並作為結果傳回。
// Existing object 
var obj = { 
 hello: function( name ) { 
  alert( "Hello " + name ); 
 } 
}, 
// Create a Deferred 
defer = $.Deferred(); 
 
// Set object as a promise 
defer.promise( obj ); 
 
// Resolve the deferred 
defer.resolve( "John" ); 
 
// Use the object as a Promise 
obj.done(function( name ) { 
 this.hello( name ); // will alert "Hello John" 
}).hello( "Karl" ); // will alert "Hello Karl" 

deferred.promise() 只是阻止其他程式碼來改變這個 deferred 物件的狀態。可以理解成,透過deferred.promise() 方法返回的deferred promise 對象,是沒有resolve ,reject, progress , resolveWith, rejectWith , progressWith 這些可以改變狀態的方法,你只能使用done, then ,fail 等方法添加handler或判斷狀態。

deferred.promise() 改變不了 deferred 物件的狀態,作用也不是保證目前的狀態不變,它只是保證你不能透過 deferred.promise() 傳回的 deferred promise 物件改變 deferred 物件的狀態。如果我們這個地方直接回傳 dtd,也是可以工作的,.done 的處理函數還是會等到 dtd.resolve() 之後才會執行.

具體在那篇部落格的例子, 如果我們把程式碼改成如下的形式:

var dtd = $.Deferred(); // 新建一个deferred对象
var wait = function(dtd){
  var tasks = function(){
    alert("执行完毕!");
    dtd.resolve(); // 改变deferred对象的执行状态
  };
  setTimeout(tasks,5000);
  return dtd;
};
$.when(wait(dtd))
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出错啦!"); });

這樣的執行結果和先前返回 dtd.promise 的結果是一樣的。

差別在什麼地方呢?如果我們把 $.when 的這塊的程式碼改成這樣的:

var d = wait(dtd);
$.when(d)
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出错啦!"); });
d.resolve();

我們會發現 alert(“哈哈,成功了!”) 會立即執行,“執行完畢”卻需要5秒後才彈出來。

但是如果我們 wait 函數最後是 return dtd.promise() 這裡 d.resolve() 就會報錯了,因為物件 d 不存在 resolve() 方法。

同樣如果我們把程式碼改成:

var dtd = $.Deferred(); // 新建一个deferred对象
var wait = function(dtd){
  var tasks = function(){
     alert("执行完毕!");
     dtd.resolve(); // 改变deferred对象的执行状态
   };
   setTimeout(tasks,5000);
   return dtd.promise();
};
dtd.resolve();
$.when( wait(dtd))
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出错啦!"); });

我們也可以發現alert(“哈哈,成功了!”) 會立即執行,因為dtd 這個deferred 物件在被傳入wait 之前,已經被resolve() 了,而deferred 物件一旦被resolve 或者reject 之後,狀態是不會改變的。

然後我們再把 $.wait 這塊的程式碼改成:

$.when( wait(dtd))
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出错啦!"); });
dtd.resolve();

我們也會發現alert(“哈哈,成功了!”); 被立即執行,雖然wait(dtd) 執行的時候, dtd 還沒有被resolve,而且wait 方法返回的是dtd.promise(), 但是dtd 這個原始的deferred 物件是暴露在外面的,我們還是可以從外面改變它的狀態。

於是,如果我們真的不想讓其他程式碼能改變 wait 方法內部的 deferred 物件的狀態,那我們應該寫成這樣:

var wait = function(){
  var dtd = $.Deferred(); // 新建一个deferred对象
  var tasks = function(){
    alert("执行完毕!");
     dtd.resolve(); // 改变deferred对象的执行状态
   };
   setTimeout(tasks,5000);
   return dtd.promise();
};
$.when( wait())
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出错啦!"); });

也就是不要把 deferred 直接暴露出來,最後回傳 deferred.promise() ,讓其他地方的程式碼只能加上 handler 。


.promise()

首先這不是Deferred實例的方法! 該方法是jQuery實例的方法。此方法用於一組類型的動作(例如動畫)全部完成後返回一個Promise對象,供事件監聽器監聽其狀態並執行相應的處理函數。

此方法接受兩個可選參數:.promise( [type,] [target] )

type:隊列的類型,預設值是fx,fx即jQuery物件的動畫.
targetObject :要賦予Promise行為的對象,

這兩個參數是可選的。其中第一個參數(我)目前除了fx還沒有找到其他的值類型。因此一般都是用於動畫的監控,在動畫完成後做一些操作。

範例:沒有動畫效果直接回傳一個resolved狀態的promise物件

var div = $( "<div />" ); 

div.promise().done(function( arg1 ) { 
 // 将会被马上触发 
 alert( this === div && arg1 === div ); 
}); 

範例:在動畫效果全部完成後觸發done()監聽函式

<!DOCTYPE html> 
<html> 
<head> 
 <style> 
div { 
 height: 50px; width: 50px; 
 float: left; margin-right: 10px; 
 display: none; background-color: #090; 
} 
</style> 
 <script src="http://code.jquery.com/jquery-latest.js"></script> 
</head> 
<body> 
  
<button>Go</button> 
<p>Ready...</p> 
<div></div> 
<div></div> 
<div></div> 
<div></div> 
<script> 
$("button").bind( "click", function() { 
 $("p").append( "Started..."); 
 //每个div执行动画效果 
 $("div").each(function( i ) { 
  $( this ).fadeIn().fadeOut( 1000 * (i+1) ); 
 }); 
 //$("div")包含一组div,在所有的div都完成自己的动画效果后触发done()函数 
 $( "div" ).promise().done(function() { 
  $( "p" ).append( " Finished! " ); 
 }); 
}); 
</script> 
 
</body> 
</html> 

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn