「这是我参与2022首次更文挑战的第27天,活动详情查看:2022首次更文挑战」
它一种规范,只要实现这种规范就可以是promise。js的Promise就是一种PromiseA+的实现。 想要手写一个promise,是不是得先了解一下其规范,下面是我把原规范,用自己的理解简化了一下,可能与原规范有出入。
主要概念
- ps 具有then方法的对象或函数,且这个方法符合本A+规范
- thenable 具有then方法的对象或函数
- value 合法的js数据类型值,包括以上两者和undefined
- exception throw抛出的(异常)值
- reason 一个值,表示拒绝理由
必要规范
承诺状态
一个ps必须处于 待处理、兑现、拒接这三种状态之一。待处理可转为兑现或拒绝,不可逆转。
兑现时要兑现一个确切的值(价值) ,拒绝同样有一个确切的值,只不过叫法不同,称为拒绝理由。
then方法
ps的then方法接收两个参数,都是可选参数,期望是函数,如果不是函数会被忽略。 第一个回调表示兑现的回调,第二个则是拒绝。 作为函数时,应当没有自己的this,严格模式下为undefined,一般情况下为全局对象。 (所以,我们jsl里面都是用箭头函数啊,绝配)
这两个回调函数都必须在ps实例兑现或决绝之后才能执行,并且至多执行一次。执行回调时,必须以第一个参数作为兑现价值或者拒绝理由。
这两个回调只能在执行上下文栈只包含平台代码的时候才能执行。 (这就是为什么【promise】是微任务)
then方法可以调用多次。但是,当ps的状态改变时,全部对应的兑现和拒绝回调都要执行,按then方法的调用顺序。
then的返回值必须是一个ps实例。
如果回调抛出异常,则返回的ps必须以这个异常作为拒绝理由(状态自然是拒绝)。
如果回调正常,返回的ps必须和源ps的状态一致,价值或理由一致。 (原本的promise变成什么样子,返回的就是一个样)
解决承诺(拒绝/兑现)
注意: 这里的解决是拒绝或兑现,不是js的resolve
假设实例P1 的兑现价值或者拒绝理由是x, then的两个参数是,res,rej. 那么:
-
如果x和P1是同一个引用(也就是 P1 === x),抛出typeError作为拒绝理由。 也就是rej(typeError)
-
如果x 是一个ps实例,那么必须等到x拒绝或兑现,才能兑现/兑现P1 . 这种情况就是回调嵌套转promise链式语法
-
如果x 是一个函数或对象(应该就是前面的thenable),那么用x.then替代这个then。 如果是对象但x.then不是函数或者找不到,那么以此为理由拒绝。 3.1 如果x.then是一个函数, 执行时以x作为其this,还是把res rej作为新的then的第一、二参数。如果res rej都被触发了,那么以最先触发的为准改变ps的状态, 后面的忽略。
-
如果 x 不是函数或对象,直接解决,将x作为价值或者理由即可。
-
then的链式调用不应有长度限制,也就是说假如每次都调用不同的then 方法无限循环是符合规范的。
所谓平台代码,包含工工程,环境和promise执行的代码。实际上,这就要求解决承诺必须是异步的,必须在一轮事件轮循的后面,并且开启一个新的执行栈(也就是不在主体代码的执行栈中嵌套)。