Promise
Promise理论知识
promise本质 不是控制 异步代码的执行顺序(无法控制) , 而是控制异步代码结果处理的顺序
Promise是什么?
-
抽象表达
-
Promise是一门新的技术(ES6规范)
-
Promise是JS中进行异步编程的新解决方案(旧方案:使用回调函数)
- 异步编程
- fs 文件操作
- 数据库操作
- AJAX
- 定时器
- 异步编程
-
-
具体表达
- 从语法上来说:Promise是一个构造函数
- 从功能上来说:promise对象用来封装一个异步操作并可以获取其==成功/失败==的结果值
为什么用Promise?(优点)
-
指定回调函数的方式更加灵活
旧的:必须在启动异步任务前指定
promise:启动异步任务 -> 返回promise对象 -> 给promise对象绑定回调函数(甚至可以再异步任务结束后指定/多个)
-
支持链式调用,解决回调地狱问题
Promise的状态
-
PromiseState
:状态是Promise
实例对象的一个属性,该属性有三个值pending 未决定的 resolved / fullfiled 成功 rejected 失败
-
状态的改变路径为:
-
pending -> resolved
-
pending -> rejected
-
-
说明
-
状态改变只有上面两种,且一个promise对象只能改变一次
-
无论变为成功还是失败,都会有一个结果数据
-
成功的数据一般称为value,失败的结果数据一般称为reason
-
Promise对象的值
PromiseResult
是Promise
实例对象的另一个属性,它保存着对象==成功或失败的==的结果。-
resovle
- reject
Promise的基本流程
https://www.bilibili.com/video/BV1GA411x7z1/?p=13&spm_id_from=pageDriver&vd_source=dde2f4dd432156027fedf9b1734ba705
如何使用Promise
API
-
Promise.prototype.then()
-
定义
then
方法定义在原型对象Promise.prototype
上,所以promise
实例可以调用then
方法。 -
作用
为
Promise
实例添加状态改变时的回调函数 -
返回值:返回一个新的
promise
实例对象
-
关键问题
-
如何改变promise对象的状态?
const p = new Promise({ // 1.改变为成功fulfilled/resovled resove('OK') // 2.改变为失败rejected reject('error') // 3.改变为失败 throw '出问题了' })
-
一个promise对象指定多个回调函数,即多个then方法,都会执行吗?
当promise对象状态改变为回调函数对应的状态时,==都会执行==。
let p = new Promise((resove, reject) => { resove('OK') }) // 当p的状态改变为成功时,下面两个回调都会执行 // 若将resove('OK')注释掉,那么下面两个回调不会执行;因为promise对象状态没发生改变 p.then(value => console.log(value)) p.then(value => alert(value))
如果是链式调用,那么会按照顺序执行
then
。 -
改变promise状态和指定回调函数谁先谁后?
注意区分执行回调函数和指定回调函数这两个概念。
-
回调函数的执行肯定是在promise对象状态改变之后
-
但是回调函数的指定与状态的改变顺序是不确定的。
- 都有可能,正常情况下是先指定回调再改变状态,但也有可能先改变状态再指定回调。
- 如何先改变状态再指定回调?
- 在执行器中直接调用
resolve(),reject()
- 延迟更长的时间才调用
then()
- 在执行器中直接调用
什么时候拿到数据,也就是回调函数什么时候执行?
- 如果先指定回调,那么当状态发生改变时,回调函数就会调用,得到数据
- 如果先改变状态,那么指定回调时,就会执行回调,得到数据
-
-
peomise.then()返回的新promise的结果状态由什么决定?
then方法会返回一个新的promise对象
- 简单表达:由then中回调函数的结果决定
- 详细表达:
- 如果抛出异常,新promise变成rejected,reason为抛出异常
- 如果返回的是非promise对象的任意值,新的promise变为resolved,value为返回值
- 如果返回的是promise对象,此promise的结果会成为新的promise的结果,该promise的状态和结果决定了新promise的结果和状态
-
promise如何串联多个操作任务?
- promise的then()函数返回一个新的promise对象,因此可以开成.then()的链式调用
- 通过then的链式调用串联多个同步/异步任务
-
promise异常穿透?
-
当使用promise的then链式调用时,可以在最后指定失败的回调,即catch
-
前面的任何操作出了异常,都会传到最后的失败的回调中处理
不考虑顺序
const p = new Promise((resolve, reject) => { // resolve('ok') reject('error') }) // 直接输出最后一个捕捉错误的catch p.then((value) => { console.log('@1', value); return value }).then((value) => { console.log('@2', value); }).catch((error) => { console.log(error); })
-
-
中断promise链
- 需求:当使用promise的then链式调用时,在中间终端,不再调用后面的回调函数
- 唯一方法:在回调函数中返回一个
pendding
状态的promise
对象- 只有返回pendding状态的
promise
对象才可以终端promise
链 pendding
状态的promise
对象,它的then方法无法执行
- 只有返回pendding状态的
const p = new Promise((resolve, reject) => { resolve('ok') // reject('error') }) p.then((value) => { console.log('@1', value); // 返回一个pendding状态的promise return new Promise(() => { }) // 后面的then不再执行 }).then((value) => { console.log('@2', value); }).catch((error) => { console.log(error); })
自定义(手写)Promise
自己手写封装Promiese的全部功能。
async和await
Promise虽然摆脱了回调地狱,但是then的链式调⽤也会带来额外的阅读负担,并且Promise传递中间值⾮常麻烦。
async函数
-
async的函数返回对象是一个
promise
对象-
返回的
promise
对象的结果 由async
函数执行的返回值return
决定 -
async和then方法的返回对象规则是一样的
-
await函数
-
await
右侧的表达式一般是promise
对象,但也可以是其他值-
如果右侧表达式是
promise
对象,await
返回的是promise
成功的值 -
如果右侧表达式是其他值,直接将此值作为
await
的返回值 -
如果
await
的promise
失败了,就会抛出异常,需要通过try...catch
处理// 将可能失败部分的代码包裹在try...catch中 try { const res3 = await p2 console.log(p2); } catch (error) { console.log(error); }
-
注意
await
必须写在async
函数中,但async
函数中可以没有await
。只有当await后面的异步操作执行完毕后,才会继续执行后面代码,因此保证了顺序。
同时,在错误处理方面,用async/await
会比的纯回调函数更方便,只需要使用try...catch
包裹代码即可。
而且,在async/await
方法中在,看不到回调函数形式的代码。