Promise规范及其应用
以下是关于学习promise A+规范的一些心得体会,以及手撕promise、实现一个promise等总结。
一:Promise A+ 规范
规范就是在我们实现的过程中需要遵循的一些规则,可能是比较枯燥但是却是进行理解基础,只有知道了定义此规范的人是如何思考的,才能以不变应万变,应对在开发过程中遇到的各种坑。
以下是一些在规范中提到的术语,了解了这部分术语,有利于我们更加后面的理解学习
-
promise :是一个有then方法的对象或函数,它的行为遵循promise A+规范;
-
thenable:也是一个有then方法的对象或者函数;
-
value :promise状态成功时候的值,也就是promise中resolve的参数;可以是各种数据类型:undefined/number/boolean/promise/string等等,都可。
const promise = new Promise((resolve, reject) => { // 其中resolve中的参数‘value’就是value,value类型可为上诉任意一种。 resolve('value') })
-
reason :promise状态失败时的值,也就是reject的参数,表示执行失败(拒绝)的原因;
const promise = new Promise((resolve, reject) => { // 其中reject中的参数‘reason’就是reason。执行失败的原因。 reject('reason') })`
-
exception :异常,抛出去的异常(throw);
promise A+规范(具体规则):
1、promise的状态 status
resolve、reject是动作,(一般是函数);而pending、fulfilled、rejected是状态,是动作的结果。
-
promise有三种状态:pending、fulfilled、resolved。
-
pending:promise的初始状态,一个promise刚被初始化出来之后,未执行其他操作,就是pending状态(==》被resolve或者reject之前的状态)。pending状态可改变,可通过resolve变为fulfilled状态;通过reject 变为rejected状态。
-
fulfilled:一个最终态,不可对其再进行改变;如何变为fulfilled?一个promise经过resolve之后就可以改变;必须拥有一个value值,resolve(value),其中value必选。
const promise = new Promise((resolve, reject) => { // 其中resolve中的参数必选,resolve()其实就相当于传入一个undefined==》等同于resolve(undefined)。 resolve(); })
-
rejected:一个最终态,不可对其再进行改变;如何变为rejected?一个promise经过reject之后就可以改变;必须拥有一个reason值,reject(reason),其中reason必选。
const promise = new Promise((resolve, reject) => { // 其中reject中的参数必选,reject()其实就相当于传入一个undefined==》等同于reject(undefined)。 reject(); })
状态流转的过程: 1、pending ---》resolve(value)---》fulfilled; 2、pending ---》reject(reason)---》rejected;
. 2、then
1、promise应该提供一个then方法,用来访问最终的结果(无论是value还是reason);常规来说reject(reason)应该是进入catch函数的,但是catch正常执行之后会再返回一个promise,这时这个promise再.then的时候也会去接受到reason---》即只需要再catch中返回reason,啥都不return,相当于return了一个undefined。
2、then函数可以接受两个参数,promise.then(onFulfilled, onRejected);
-
then函数的两个参数要求:
1)、onFulfilled:必须是函数类型,如果不是函数类型,则应该被忽略,(具体如何忽略,见下文)
2)、onRejected:必须是函数类型,如果不是函数类型,也应该被忽略。(见下文) -
onFulfilled特性
1)promise状态变为fulfilled时,应该调用onFulfilled函数,参数时value。
2)promise状态变为fulfilled之前,不应该被调用。
3)只能被调用一次。(需要一个变量来限制执行的次数) -
onRejected特性
1)promise状态变为rejected时,应该调用onRejected函数,参数时reason。
2)promise状态变为rejected之前,不应该被调用。
3)只能被调用一次。(需要一个变量来限制执行的次数) -
onFulfilled和onRejected应该是微任务,(使用queueMicrotask来实现微任务的调用)
-
then方法可以被多次调用:
1)promise状态变为fulfilled的时候,所有的onFulfilled的回调函数都应该按照then的顺序来执行;伪代码:eg1:promise.then(cb1).then(cb2).then(cb3),回调的执行顺序:cb1、cb2、cb3 eg2:const promise = new Promise((resolve, reject) => {...}); promise.then(); promise.then(); 上述伪代码中,可以先new一个promise,然后再同一个promise上面挂载多个then,也算是then方法一直调用的实现。 =》多次then调用之后,对应的callback应该怎么存?? 由于是挂载在同一个promise上,需要一个数组来存储onFulfilled的回调函数,这样可以将多个回调函数存在同一个地方,同时数组可以确定执行的顺序。
2)promise状态变为rejected的时候,所有的onRejected的回调函数都应该按照then的顺序来执行;(这里都用then,因为then可以接受两个参数,第二个表示onRejected,也可省略,即为null);同上,同样需要一个数组来存储。
-
then的返回值:promise(新的)
1)onFulfilled或者onRejected函数的执行结果是 x,然后去调用对应的resolvePromise。
(resolvePromise—》理解:用来真正将promise的状态变更执行的方法(相当于一个底层更改状态的函数—》本人理解,有其他更好的理解欢迎指出!))
2)onFulfilled或者onRejected执行时抛出异常,promise2(也就是这个新的promise)需要被reject。
3)如果onFulfilled不是一个函数,promise2就会以promise1的value触发fulfilled—《状态变更为filfilled,接收promise1的value,promise1是啥promise2就是啥》
4)如果onRejected不是一个函数,promise2就会以promise1的reason触发rejected—《状态变更为rejected,接收promise1的reason,promise1是啥promise2就是啥》 -
resolvePromise
resolvePromise(promise2,x,resolve,reject)
1)如果promise2和 x 相等,则reject TypeError。(因为promise2 和 x 相等的话,会造成死循环)2)如果 x 是是一个promise:
1、如果 x 是pending,(因为一个promise的初始状态必须为pending),则必须等到 x 的状态变为fulfilled或者是rejected。 2、如果 x 是fulfilled,就不需要等待了,直接将x promise的value透传到外界的promise2中,并且状态更改为fulfilled。 3、如果 x 是rejected,就不需要等待了,直接将x promise的reason透传到外界的promise2中,并且状态更改为rejected。
3)如果 x 是一个Object 或者 是一个 function:
1、let then = x.then; // 会去判断这一步的赋值是否会报错,(如果x.then这一步出错了,try catch(e), 抛出一个错误,那么就直接reject(e)) 2、如果获取到的then是一个函数,则直接以当前的这个 x 去调用即可。 then.call(x, resolvePromiseFn, rejectPromiseFn) resolvePromiseFn: 入参是y,执行 resolvePromise(promise2, y, resolve, reject); 这个y就是一个名称而已,取其他的是一样的,其实就是相当于 x 去调用then的时候会有返回的执行结果,就取值为了 y 。 如果调用.then的时候抛出了异常,如果此时的resolvePromiseFn和rejectPromiseFn已经执行完成了,则不用去管这个了; 如果未执行完成,则需要reject 一个reason。