promiseA+是什么

128 阅读3分钟

「这是我参与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. 那么:

  1. 如果x和P1是同一个引用(也就是 P1 === x),抛出typeError作为拒绝理由。 也就是rej(typeError)

  2. 如果x 是一个ps实例,那么必须等到x拒绝或兑现,才能兑现/兑现P1 . 这种情况就是回调嵌套转promise链式语法

  3. 如果x 是一个函数或对象(应该就是前面的thenable),那么用x.then替代这个then。 如果是对象但x.then不是函数或者找不到,那么以此为理由拒绝。 3.1 如果x.then是一个函数, 执行时以x作为其this,还是把res rej作为新的then的第一、二参数。如果res rej都被触发了,那么以最先触发的为准改变ps的状态, 后面的忽略。

  4. 如果 x 不是函数或对象,直接解决,将x作为价值或者理由即可。

  5. then的链式调用不应有长度限制,也就是说假如每次都调用不同的then 方法无限循环是符合规范的。

所谓平台代码,包含工工程,环境和promise执行的代码。实际上,这就要求解决承诺必须是异步的,必须在一轮事件轮循的后面,并且开启一个新的执行栈(也就是不在主体代码的执行栈中嵌套)。