这次聊聊Promise对象

qcloudcommunity · · 668 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

**欢迎大家前往[腾讯云+社区](https://cloud.tencent.com/developer/?fromSource=waitui),获取更多腾讯海量技术实践干货哦~** > 本文由[前端林子](https://cloud.tencent.com/developer/user/2221081)发表于[云+社区专栏](https://cloud.tencent.com/developer/column/5154?fromSource=waitui) Promise是CommonJS提出的一种规范,在ES6中已经原生支持Promise对象,非ES6环境可以用Bluebird等库来支持。 # 0.引入 在js中任务的执行模型有两种:同步模式和异步模式。 **同步模式**:后一个任务B等待前一个任务A结束后,再执行。任务的执行顺序和任务的排序顺序是一致的。 **异步模式**:每一个任务有一个或多个回调函数,前一个任务A结束后,不是执行后一个任务B,而是执行任务A的回调函数。而后一个任务B是不等任务A结束就执行。任务的执行顺序,与任务的排序顺序不一致。 异步模式编程有四种方法:回调函数(最基本的方法,把B写成A的回调函数)、事件监听(为A绑定事件,当A发生某个事件,就执行B)、发布/订阅,以及本文要介绍的Promise对象。 Promise是**一个用于处理异步操作的对象**,可以将回调函数写成链式调用的写法,让代码更优雅、流程更加清晰,让我们可以更合理、更规范地进行异步处理操作。它的思想是,每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数。 # 1.Promise的基本知识 ## 1.1 三种状态 Pending:进行中,刚创建一个Promise实例时,表示初始状态; resolved(fulfilled):resolve方法调用的时候,表示操作成功,已经完成; Rejected:reject方法调用的时候,表示操作失败; ## 1.2 两个过程 这三种状态只能从pendeng-->resolved(fulfilled),或者pending-->rejected,不能逆向转换,也不能在resolved(fulfilled)和rejected之间转换。并且一旦状态改变,就不会再改变,会一直保持这个结果。 汇总上述,创建一个Promise的实例是这样的: ```js //创建promise的实例 let promise = new Promise((resolve,reject)=>{ //刚创建实例时的状态:pending if('异步操作成功'){ //调用resolve方法,状态从pending变为fulfilled resolve(); }else{ //调用reject方法,状态从pending变为rejected reject(); } }); ``` ## 1.3 then() 用于绑定处理操作后的处理程序,分别指定fulfilled状态和rejected状态的回调函数,即它的参数是两个函数,第一个用于处理操作成功后的业务,第二个用于处理操作失败后的业务。 ```js //then() promise.then((res)=> { //处理操作成功后的业务(即Promise对象的状态变为fullfilled时调用) },(error)=> { //处理操作失败后的业务(即Promise对象的状态变为rejected时调用) }); ``` ## 1.4 catch() 用于处理操作异常的程序,catch()只接受一个参数 ```js //catch() promise.catch((error)=> { //处理操作失败后的业务 }); ``` 一般来说,建议不要在then()里面定义rejected状态的回调函数,而是将then()用于处理操作成功,将catch()用于处理操作异常。因为这样做可以捕获then()执行中的错误,也更接近同步中try/catch的写法: ```js //try-catch // bad promise.then((res)=> { //处理操作成功后的业务 }, (error)=> { //处理操作失败后的业务 }); // good promise .then((res)=> { //处理操作成功后的业务 }) .catch((error)=> { //处理操作失败后的业务 }); ``` ## 1.5 all() 接受一个数组作为参数,数组的元素是Promise实例对象。只有当参数中的实例对象的状态都为fulfilled时,Promise.all( )才会有返回。 实例代码(可直接在浏览器中打开): ```js <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Promise实例</title> <style type="text/css"></style> <script type="text/javascript"> window.onload = () => { //创建实例promise1 let promise1 = new Promise((resolve) => { setTimeout(() => { resolve('promise1操作成功'); console.log('1') }, 3000); }); //创建实例promise1 let promise2 = new Promise((resolve) => { setTimeout(() => { resolve('promise1操作成功'); console.log('2') }, 1000); }); Promise.all([promise1, promise2]).then((result) => { console.log(result); }); } </script> </head> <body> <div></div> </body> </html> ``` 结果(注意看时间): ![img](https://ask.qcloudimg.com/draft/2221081/jl5656iw4b.png?imageView2/2/w/1620)Promise.all() 代码说明: 1s后,promise2进入fulfilled状态,间隔2s,也就是3s后,promise1也进入fulfilled状态。这时,由于两个实例都进入了fulfilled状态,所以Promise.all()才进入了then方法。 > 使用场景:执行某个操作需要依赖多个接口请求回的数据,且这些接口之间不存在互相依赖的关系。这时使用Promise.all(),等到所有接口都请求成功了,它才会进行操作。 ## 1.6 race() 和all()的参数一样,参数中的promise实例,只要有一个状态发生变化(不管是成功fulfilled还是异常rejected),它就会有返回,其他实例中再发生变化,它也不管了。 实例代码(可直接在浏览器中打开): ```js <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Promise实例</title> <style type="text/css"></style> <script type="text/javascript"> window.onload = () => { //创建实例promise1 let promise1 = new Promise((resolve) => { setTimeout(() => { resolve('promise1操作成功'); console.log('1') }, 3000); }); //创建实例promise1 let promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('promise1操作失败'); console.log('2') }, 1000); }); Promise.race([promise1, promise2]) .then((result) => { console.log(result); }) .catch((error) => { console.log(error); }) } </script> </head> <body> <div></div> </body> </html> ``` 结果(注意看时间): ![img](https://ask.qcloudimg.com/draft/2221081/heosmlrae0.png?imageView2/2/w/1620)Promise.race() 代码说明: 1s后,promise2进入rejected状态,由于一个实例的状态发生了变化,所以Promise.race()就立刻执行了。 # 2 实例 平时开发中可能经常会遇到的问题是,要用ajax进行多次请求。例如现在有三个请求,请求A、请求B、请求C。请求C要将请求B的请求回来的数据做为参数,请求B要将请求A的请求回来的数据做为参数。 按照这个思路,我们可能会直接写出这样的层层嵌套的代码: ```js //------请求A 开始--------- $.ajax({ success:function(res1){ //------请求B 开始---- $.ajax({ success:function(res2){ //----请求C 开始--- $.ajax({ success:function(res3){ } }); //---请求C 结束--- } }); //------请求B 结束----- } }); //------请求A 结束--------- ``` 在请求A的success后,请求B发送请求,在请求B 的success后,请求C发送请求。请求C结束后,再向上到请求B结束,请求B结束后,再向上到请求A结束。 这样虽然可以完成任务,但是代码层层嵌套,代码可读性差,也不便于调试和后续的代码维护。而如果用Promise,你可以这样写(示意代码,无ajax请求): 此处附上完整可执行代码,可在浏览器的控制台中查看执行结果: ```js <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Promise实例</title> <style type="text/css"></style> <script type="text/javascript"> window.onload = () => { let promise = new Promise((resolve, reject) => { if (true) { //调用操作成功方法 resolve('操作成功'); } else { //调用操作异常方法 reject('操作异常'); } }); //then处理操作成功,catch处理操作异常 promise.then(requestA) .then(requestB) .then(requestC) .catch(requestError); function requestA() { console.log('请求A成功'); return '下一个是请求B'; } function requestB(res) { console.log('上一步的结果:' + res); console.log('请求B成功'); return '下一个是请求C'; } function requestC(res) { console.log('上一步的结果:' + res); console.log('请求C成功'); } function requestError() { console.log('请求失败'); } } </script> </head> <body> <div></div> </body> </html> ``` 结果如下: ![img](https://ask.qcloudimg.com/draft/2221081/xivdtpgxhz.png?imageView2/2/w/1620)实例 可以看出请求C依赖请求B的结果,请求B依赖请求A的结果,在请求A中是使用了return将需要的数据返回,传递给下一个then()中的请求B,实现了参数的传递。同理,请求B中也是用了return,将参数传递给了请求C。 # 3.小结 本文主要介绍了Promise对象的三个状态和两个过程。“三个状态”是:初始化、操作成功、操作异常,“两个过程”是初始化状态到操作成功状态,和初始化状态到操作异常状态。除此之前,还有两种实例方法:then()、catch()来绑定处理程序。类方法:Promise.all()、Promise.race()。如有问题,欢迎指正。 >**相关阅读** >[【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识](https://cloud.tencent.com/developer/edu/course-1128?fromSource=waitui) **此文已由作者授权腾讯云+社区发布,更多原文请[点击](https://cloud.tencent.com/developer/article/1359152?fromSource=waitui )** **搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复1024 送你一份技术课程大礼包!** 海量技术实践经验,尽在[云加社区](https://cloud.tencent.com/developer?fromSource=waitui)!

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

668 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传