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


Posted in Javascript onMay 03, 2016

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>
Javascript 相关文章推荐
JavaScript 格式字符串的应用
Mar 29 Javascript
JS解析json数据并将json字符串转化为数组的实现方法
Dec 25 Javascript
jquery $.fn $.fx是什么意思有什么用
Nov 04 Javascript
js实现省市联动效果的简单实例
Feb 10 Javascript
Jquery 1.9.1源码分析系列(十二)之筛选操作
Dec 02 Javascript
BootStrap iCheck插件全选与获取value值的解决方法
Aug 24 Javascript
Vue服务端渲染和Vue浏览器端渲染的性能对比(实例PK )
Mar 31 Javascript
js实现一个简单的MVVM框架示例
Jan 15 Javascript
JavaScript实现微信号随机切换代码
Mar 09 Javascript
vue给对象动态添加属性和值的实例
Sep 09 Javascript
javascript实现前端input密码输入强度验证
Jun 24 Javascript
三步搞定:Vue.js调用Android原生操作
Sep 07 Javascript
浅析函数声明和函数表达式——函数声明的声明提前
May 03 #Javascript
详解JavaScript异步编程中jQuery的promise对象的作用
May 03 #Javascript
jQuery的promise与deferred对象在异步回调中的作用
May 03 #Javascript
JavaScript的MVVM库Vue.js入门学习笔记
May 03 #Javascript
聊一聊JavaScript作用域和作用域链
May 03 #Javascript
小白谈谈对JS原型链的理解
May 03 #Javascript
基于Bootstrap使用jQuery实现输入框组input-group的添加与删除
May 03 #Javascript
You might like
咖啡语言
2021/03/03 咖啡文化
CI框架出现mysql数据库连接资源无法释放的解决方法
2016/05/17 PHP
使用JavaScript创建新样式表和新样式规则
2016/06/14 PHP
php中文字符串截取多种方法汇总
2016/10/06 PHP
微信公众平台开发教程③ PHP实现微信公众号支付功能图文详解
2019/04/10 PHP
Laravel 不同生产环境服务器的判断实践
2019/10/15 PHP
深入理解PHP+Mysql分布式事务与解决方案
2020/12/03 PHP
js 函数的执行环境和作用域链的深入解析
2009/11/01 Javascript
suggestion开发小结以及对键盘事件的总结(针对中文输入法状态)
2011/12/20 Javascript
jquery的attr方法禁用表单元素禁用输入内容
2014/06/23 Javascript
js使用正则实现ReplaceAll全部替换的方法
2014/08/22 Javascript
JavaScript阻止浏览器返回按钮的方法
2015/03/18 Javascript
jQuery实现向下滑出的二级菜单效果实例
2015/08/22 Javascript
基于Bootstrap实现的下拉菜单手机端不能选择菜单项的原因附解决办法
2016/07/22 Javascript
修改Jquery Dialog 位置的实现方法
2016/08/26 Javascript
AngularJS 实现弹性盒子布局的方法
2016/08/30 Javascript
编写更好的JavaScript条件式和匹配条件的技巧(小结)
2019/06/27 Javascript
使用vue中的混入mixin优化表单验证插件问题
2019/07/02 Javascript
vue css 引入asstes中的图片无法显示的四种解决方法
2020/03/16 Javascript
JavaScript链式调用原理与实现方法详解
2020/05/16 Javascript
Python实现基于TCP UDP协议的IPv4 IPv6模式客户端和服务端功能示例
2018/03/22 Python
Django中提供的6种缓存方式详解
2019/08/05 Python
使用python批量修改文件名的方法(视频合并时)
2020/03/24 Python
在Keras中利用np.random.shuffle()打乱数据集实例
2020/06/15 Python
Win10下用Anaconda安装TensorFlow(图文教程)
2020/06/18 Python
Blue Nile中国官网:全球知名的钻石和珠宝网络零售商
2020/03/22 全球购物
芭比波朗加拿大官方网站:Bobbi Brown Cosmetics CA
2020/11/05 全球购物
戴尔荷兰官方网站:Dell荷兰
2020/10/04 全球购物
介绍一下gcc特性
2012/01/20 面试题
高中自我评价范文
2014/01/27 职场文书
《尊严》教学反思
2014/02/11 职场文书
庆祝儿童节标语
2014/10/09 职场文书
房屋授权无偿使用证明
2014/11/29 职场文书
2016教师国培研修感言
2015/12/08 职场文书
《卧薪尝胆》读后感3篇
2019/12/26 职场文书
新的CSS 伪类函数 :is() 和 :where()示例详解
2022/08/05 HTML / CSS