深入解析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 相关文章推荐
把textarea中字符串里含有的回车换行替换成&amp;lt;br&amp;gt;的javascript代码
Apr 20 Javascript
JS无法捕获滚动条上的mouse up事件的原因猜想
Mar 21 Javascript
jquery实现漂浮在网页右侧的qq在线客服插件示例
May 13 Javascript
js替换字符串的所有示例代码
Jul 23 Javascript
ExtJs中gridpanel分组后组名排序实例代码
Dec 02 Javascript
js限制checkbox选中个数以限制六个为例
Jul 15 Javascript
js实现图片和链接文字同步切换特效的方法
Feb 20 Javascript
Bootstrap简单表单显示学习笔记
Nov 15 Javascript
JS验证全角与半角及相互转化的介绍
May 18 Javascript
详解a++和++a的区别
Aug 30 Javascript
express+mockjs实现模拟后台数据发送功能
Jan 07 Javascript
在Layui 的表格模板中,实现layer父页面和子页面传值交互的方法
Sep 10 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
开发大型PHP项目的方法
2006/10/09 PHP
对象失去焦点时自己动提交数据的实现代码
2012/11/06 PHP
php实现获取文章内容第一张图片的方法
2014/11/04 PHP
jquery下动态显示jqGrid以及jqGrid的属性设置容易出现问题的解决方法
2010/10/22 Javascript
Javascript 颜色渐变效果的实现代码
2013/10/01 Javascript
JavaScript操作DOM元素的childNodes和children区别
2015/04/01 Javascript
jquery中toggle函数交替使用问题
2015/06/22 Javascript
javascript实现确定和取消提示框效果
2015/07/10 Javascript
js精美的幻灯片画集特效代码分享
2015/08/29 Javascript
JavaScript面试题(指针、帽子和女朋友)
2016/11/23 Javascript
JS 对java返回的json格式的数据处理方法
2016/12/05 Javascript
BootStrapValidator初使用教程详解
2017/02/10 Javascript
jQuery阻止移动端遮罩层后页面滚动
2017/03/15 Javascript
JS简单判断滚动条的滚动方向实现方法
2017/04/28 Javascript
jQuery 实现左右两侧菜单添加、移除功能
2018/01/02 jQuery
详解Vue单元测试Karma+Mocha学习笔记
2018/01/31 Javascript
浅谈angular4.0中路由传递参数、获取参数最nice的写法
2018/03/12 Javascript
webpack 模块热替换原理
2018/04/09 Javascript
微信小程序图片左右摆动效果详解
2019/07/13 Javascript
Vue中fragment.js使用方法小结
2020/02/17 Javascript
vue+vuex+axios从后台获取数据存入vuex,组件之间共享数据操作
2020/07/31 Javascript
JS中循环遍历数组的四种方式总结
2021/01/23 Javascript
[02:16]2018年度CS GO最具人气选手-完美盛典
2018/12/16 DOTA
OpenCV HSV颜色识别及HSV基本颜色分量范围
2019/03/22 Python
Python3.5常见内置方法参数用法实例详解
2019/04/29 Python
Python3 pandas 操作列表实例详解
2019/09/23 Python
Python 爬虫性能相关总结
2020/08/03 Python
Superdry极度乾燥官网:日本街头风格,纯英国制造品牌
2016/10/31 全球购物
巴西箱包、背包、钱包和旅行配件购物网站:Inovathi
2019/12/14 全球购物
error和exception有什么区别
2012/10/02 面试题
自荐书封面下载
2013/11/29 职场文书
初中生个人学习的自我评价
2013/12/04 职场文书
个性发展自我评价
2014/02/11 职场文书
2014年文员工作总结
2014/11/18 职场文书
生产现场禁烟通知
2015/04/23 职场文书
如何写好闭幕词
2019/04/02 职场文书