搜索
首页web前端js教程jQuery的promise与deferred对象在异步回调中的作用_jquery

一、前言

为了让前端们从回调的地狱中回到天堂, jQuery 也引入了 Promise 的概念。 Promise 是一种令代码异步行为更加优雅的抽象,有了它,我们就可以像写同步代码一样去写异步代码。 jQuery 从1.5版本开始实现了 CommonJS Promise/A 规范这一重量级方案,不过没有严格按照规范进行实现,有一些API上的差异。

好,让我们来看看他们的特性吧( 本文示例基于jquery 1.8版本以上 )。

二、示例

以前写动画时,我们通常是这么干的:

$('.animateEle').animate({
 opacity:'.5'
}, 4000,function(){
 $('.animateEle2').animate({
  width:'100px'
 },2000,function(){
  // 这样太伤了
  $('.animateEle3').animate({
   height:'0'
  },2000);
 });
});

假如这么使用回调的话,那就太伤了。幸好,还有一些现成的 Promise 解决方案来优雅地解决这种问题。

我们看看 jQuery 提供的解决办法。

var animate1 = function() {
 return $('.animateEle1').animate({opacity:'.5'},4000).promise();
};
var animate2 = function() {
 return $('.animateEle2').animate({width:'100px'},2000).promise();
};
var animate3 = function(){
 return $('.animateEle3').animate({height:'0'},2000).promise();
};
// so easy,有木有,so clear,有木有
$.when(animate1()).then(animate2).then(animate3);

很明显,更改后的代码更易懂易读了。

但是,上面的代码,有些细节的东西并没有透露,一不小心,就容易出错,得不到我们想要的顺序完成动画的效果。下面让我们来全面理解 jQuery 提供的 promise 和 deferred 对象的方法,看看到底如何使用。

三、promise和deffered对象方法

promise 对象其实就是 deferred 对象的特例,因为 promise 对象不能更改异步状态,而 deferred 对象可以。这点在他们的方法设计上,有着明显的体现。

1.promise对象方法

通常,对于DOM,动画,ajax相关方法,我们都可以使用 promise 方法。调用 promise 方法,返回的是 promise 对象。可以链式调用 promise 方法。

promise对象常见的方法有三个 : done , fail , then 。

其它的方法就不要去记了, jquery 这里的接口方法太多了,在我看来挺啰嗦的,就跟早期的事件方法绑定一样, live , delegate , bind ,最终不是都归为 on 来管了么。

代码示例,如下:

(1)DOM使用 promise 方法:

var box=$('#box');
box.promise().done(function(ele){
  console.log(ele);//jQuery box
});

(2)Ajax使用 promise 方法(默认返回一个 promise 对象,所以可以不必显式调用 promise 方法):

$.post('/',{}).done(function(data){
  console.log('请求成功');
}).fail(function(){
  console.log('请求错误');
});

动画示例已有,就不重复列出了。

2.deferred对象方法

那么Deferred和Promise之间有什么区别呢?正如你在前面看到的,一个promise就是一个由异步函数返回的对象。当你想要自己编写一个这样的函数时你需要使用一个deferred。

一个deferred对象能做的和一个promise对象差不多,但是它有两个函数来触发done()和fail()函数。

一个deferred对象拥有一个resolve()函数来处理一个成功的结果并执行与done()相关的函数。reject()函数则用来处理失败的结果并执行与fail()相关的函数。

你可以给resolve()和reject()函数都提供参数,然后它们都将传递给与done()和fail()相关的回调函数。

promise对象没有resolve()和reject()函数。这是因为你将promise放到了其他的脚本中并且你也不想promise去resolve或者reject一个promise。

下面是一个关于deferred的简单例子。html仅仅是一个简单的拥有id属性为”result”的空div。

$('#result').html('waiting...');

var promise = wait();
promise.done(result);

function result() {
 $('#result').html('done');
}

function wait() {
 var deferred = $.Deferred();

 setTimeout(function() {
  deferred.resolve();
 }, 2000);

 return deferred.promise();
}  

其中,wait()函数返回了一个promise。它将在2s之后被解析。除了setTimeout之外,异步函数中所有的东西都能这样使用,比如 动画,Web worker等等。wait()函数中的代码应该很清晰,我们使用了deferred对象,但是我们返回了一个限制的promise对象。

对于 deferred 对象呢,也就是使用 $.Deferred() 方法,以及 $.when() 等方法创造出来的对象,有如下的常用方法:

resolve , reject , notify ;
done , fail , progress ;

另外还有 promise 、 then 和 always 方法。

之所以这么排版,是因为他们是对应的,也就是说: resolve 方法会触发 done 的回调执行, reject 会触发 fail 的回调, notify 会触发 progress 的回调。

直接看代码:

var wait = function(ms) {
 var dtd = $.Deferred();
 setTimeout(dtd.resolve, ms);
 // setTimeout(dtd.reject, ms);
 // setTimeout(dtd.notify, ms);
 return dtd.promise(); //此处也可以直接返回dtd
};

wait(2500).done(function() {
 console.log('haha,师太,你可让老衲久等了');
}).fail(function() {
 console.log('失败了');
}).progress(function(res) {
 console.log('等待中...');
});

我们看到了,上面的代码中,在 wait 函数中,返回的是个 promise 对象,而不是 deferred 对象。

要知道, promise 对象是没有 resolve , reject , notify 等方法的,也就意味着,你无法针对 promise 对象进行状态更改,只能在 done 或 fail 中进行回调配置。所以,你如果这么调用 wait(2500).resolve() 将会报错,因为 wait(2500) 返回的是个 promise 对象,不存在 resolve 方法。

但是,这么做,有个好处,我们把 dtd 这个 deferred 对象放在了 wai t函数中,作为了局部变量,避免了全局的污染;进一步通过 promise 方法,转化 dtd 这个 deferred 对象为 promise 对象,避免了函数 wait 外部可能发生的状态更改(假如我们确实有这个需求)。

比如:

var wait = function(ms) {
 var dtd = $.Deferred();
 setTimeout(dtd.resolve, ms);
 // setTimeout(dtd.reject, ms);
 // setTimeout(dtd.notify, ms);
 return dtd; //此处也可以直接返回dtd
};

wait(2500).reject().fail(function(){
 console.log('失败了...............');
});

我们在外部更改了 wait 返回的 deferred 对象的状态,这样必然触发该对象的 fail 回调函数。

对于 always 方法,从字面意思上就很容易理解, deferred 对象无论是 resolve 还是 reject ,都会触发该方法的回调。

3.其它共性

此处讲讲 then 和 $.when 方法的使用。它们对 promise 对象也适用。

$.when 方法接受多个 deferred 对象或者纯javascript对象,返回 promise 对象。
then 方法依次接受三个回调,分别为 deferred 对象 resolve , reject , notify 后触发的回调,返回一个 promise 对象。注意,必须传入函数,而该函数只有返回一个 promise 对象,才能够让异步事件按照预期顺序来执行。
我们来看看最开始的动画示例代码, $.when(animate1()).then(animate2).then(animate3) , $.when 方法中接受了一个 animate1 的函数执行结果,也就是得到了一个 promise 对象,而后的 then 中,则只是接受了一个变量名,这样得到的结果是一个匿名的函数体,而该函数中返回的是 promise 对象。正好符合了我们对 then 接受参数的要求。

假如我们把执行语句改成: $.when(animate1()).then(animate2()).then(animate3()) ,这样造成的结果就是三个动画同步执行了。与 $.when(animate1(),animate2(),animate3()) 无异。

既然 then 是如此要求,那么与 then 方法类似的 done , fail , progress 也是一样的。

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
JavaScript引擎:比较实施JavaScript引擎:比较实施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和执行JavaScript代码时,效果会有所不同,因为每个引擎的实现原理和优化策略各有差异。1.词法分析:将源码转换为词法单元。2.语法分析:生成抽象语法树。3.优化和编译:通过JIT编译器生成机器码。4.执行:运行机器码。V8引擎通过即时编译和隐藏类优化,SpiderMonkey使用类型推断系统,导致在相同代码上的性能表现不同。

超越浏览器:现实世界中的JavaScript超越浏览器:现实世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在现实世界中的应用包括服务器端编程、移动应用开发和物联网控制:1.通过Node.js实现服务器端编程,适用于高并发请求处理。2.通过ReactNative进行移动应用开发,支持跨平台部署。3.通过Johnny-Five库用于物联网设备控制,适用于硬件交互。

使用Next.js(后端集成)构建多租户SaaS应用程序使用Next.js(后端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务

如何使用Next.js(前端集成)构建多租户SaaS应用程序如何使用Next.js(前端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:22 AM

本文展示了与许可证确保的后端的前端集成,并使用Next.js构建功能性Edtech SaaS应用程序。 前端获取用户权限以控制UI的可见性并确保API要求遵守角色库

JavaScript:探索网络语言的多功能性JavaScript:探索网络语言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是现代Web开发的核心语言,因其多样性和灵活性而广泛应用。1)前端开发:通过DOM操作和现代框架(如React、Vue.js、Angular)构建动态网页和单页面应用。2)服务器端开发:Node.js利用非阻塞I/O模型处理高并发和实时应用。3)移动和桌面应用开发:通过ReactNative和Electron实现跨平台开发,提高开发效率。

JavaScript的演变:当前的趋势和未来前景JavaScript的演变:当前的趋势和未来前景Apr 10, 2025 am 09:33 AM

JavaScript的最新趋势包括TypeScript的崛起、现代框架和库的流行以及WebAssembly的应用。未来前景涵盖更强大的类型系统、服务器端JavaScript的发展、人工智能和机器学习的扩展以及物联网和边缘计算的潜力。

神秘的JavaScript:它的作用以及为什么重要神秘的JavaScript:它的作用以及为什么重要Apr 09, 2025 am 12:07 AM

JavaScript是现代Web开发的基石,它的主要功能包括事件驱动编程、动态内容生成和异步编程。1)事件驱动编程允许网页根据用户操作动态变化。2)动态内容生成使得页面内容可以根据条件调整。3)异步编程确保用户界面不被阻塞。JavaScript广泛应用于网页交互、单页面应用和服务器端开发,极大地提升了用户体验和跨平台开发的灵活性。

Python还是JavaScript更好?Python还是JavaScript更好?Apr 06, 2025 am 12:14 AM

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。 1.Python以简洁语法和丰富库生态着称,适用于数据分析和Web开发。 2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
4 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具