【知其所以然】详解 Promise A Plus ,从规范角度看 Promise

感觉有帮助的小伙伴请点赞👍鼓励一下 ~

前言

Promise 的规范有很多,如Promise/APromise/BPromise/D 以及 Promise/A 的升级版 Promise/A+ES6 中采用了 Promise/A+ 规范。

所以我们今天就讲一讲 Promise/A+ 规范。

任何符合 Promise 规范的对象或函数都可以成为 Promise, 我们使用的 Promise 也不过是符合 Promise/A+ 规范的其中一种形式,你也可以自己封装一个符合规范的函数,那么你写的函数也可以叫 Promise

术语

  • Promise(实例): 是具有 then 方法的对象或函数,其行为符合此规范。
  • thenable(具有then方法): 是一个定义 then 方法的对象或函数。
  • value(值): 是任意合法的 Javascript 值,(包括 undefined, thenable , promise)。
  • exception(异常): 是使用 throw 语句抛出的值。
  • reason(原因): 是表示 promise 为什么被 rejected 的原因,也就是要 throw 一个 error

要求

Promise的状态

一个 Promise 的当前状态必须为以下三种状态中的一种:等待态(Pending已完成(Fulfilled)和已拒绝(Rejected)。

  • 处于等待态时,Promise 需满足以下条件:可以变成 已完成已拒绝
  • 处于已完成时,Promise 需满足以下条件:
    • 不能迁移至其它任何状态
    • 必须拥有一个 不可变 的值
  • 处于已拒绝时,Promise 需满足以下条件:
    • 不能迁移至其它任何状态
    • 必须拥有一个 不可变 的原因

必须有一个then方法

一个 Promise 必须提供一个 then 方法以访问其当前值和原因。 也就是说当 Promise 的状态由 等待态 变为 已完成已拒绝 时,得有一个地方注册回调函数。

  • Promisethen 方法接收 两个可选参数Promise.then(onFulfilled, onRejected),两个参数必须是 函数,如果不是函数,则需要 忽略 它们。

  • onFulfilled

    • Promise 执行结束后,onFulfilled 必须被调用,其第一个参数为 Promise 的值。
    • Promise 执行结束前,onFulfilled 不可被调用。
    • onFulfilled 的调用次数不可超过一次。
  • onRejected

    • Promise 被拒绝执行后,onRejected 必须被调用,其第一个参数为 Promise 的原因。
    • Promise 被拒绝执行前,onRejected 不可被调用。
    • onRejected 的调用次数不可超过一次。
  • 在执行上下文堆栈仅包含平台代码之前,不得调用 onFulfilledonRejected ,这个跟 JavaScript 中的 Event Loop 相关,在当前的循环中,同步代码执行完之前不可以执行 onFulfilledonRejected 这两个函数。

  • onFulfilledonRejected 必须被作为普通函数调⽤(即⾮实例化调⽤(new Function),这样函数内部 this ⾮严格模式下指向 window)。

  • then ⽅法可以被同⼀个 Promise 调⽤多次:

    • Promise 成功执⾏时,所有 onFulfilled 需按照其注册顺序依次回调。
    • Promise 被拒绝执⾏时,所有的onRejected需按照其注册顺序依次回调。
  • then ⽅法必须返回⼀个 Promise 对象,promise2 = promise1.then(onFulfilled, onRejected)

    • 只要 onFulfilledonRejected 返回一个值 xpromise2 都会进⼊ onFulfilled 状态。

    • 如果 onFulfilledonRejected 抛出一个异常 e , 则 promise2 必须被拒绝执行并把 e 当作原因返回。

    • 如果 onFulfilled 不是一个函数,并且 promise1 已经完成, promise2 必须成功执行并返回相同的值。

    • 如果 onRejected 不是一个函数, 并且 promise1 已经被拒绝, promise2 必须执行拒绝回调并返回相同的拒因。

    • 下面来看一个例子。

 const promise1 = new Promise((resolve, reject) => reject())
 // promise1 手动调用 reject 置为已拒绝状态 , 此时会执行第二个参数的回调函数. 返回 123.
 promise1
   // 根据只要 `onFulfilled` 或 `onRejected` 返回一个值 `x` ,`promise2` 都会进⼊ `onFulfilled` 状态 , 值为  123.
   .then(null, () => {
     return 123
   })
   //- 根据如果 `onFulfilled` 不是一个函数,并且 `promise1` 已经完成,  `promise2` 必须成功执行并返回相同的值。 值依然为  123.
   .then(null, null)
   // 同上 值依然为  123.
   .then(null, null)
   //  根据如果 `onFulfilled` 不是一个函数,并且 `promise1` 已经完成,  `promise2` 必须成功执行并返回相同的值。 打印 promise2 已完成,123
   .then(
     (res) => { console.log('promise2 已完成', res) },  //=> promise2 已完成 123
     (res) => { console.log('promise2 已拒绝', res) }
   )

Promise的解决过程

Promise 解决程序是一个抽象操作,我们将其表示为[[Resolve]](promise, x),它以一个 promise 和一个值作为输入。 (这句话的意思就是把 promise 的状态置为 resolve ,同时传入 x 作为值)。

  promise.then((x) => {
    console.log('会执行这个函数,同时传入x变量的值', x);
  });

如果 xthen 方法且看上去像一个 Promise , 解决程序就会尝试使 Promise 接受 x 的状态,否则就用 x 的值来执行 Promise

如果 Promisex 都指向同一个对象

TypeError 为拒因拒绝执行 Promise 。这个没有实现,有大佬知道怎么回事的话,请评论区指教一下。

如果 xPromise ,则使 Promise 接受 x 的状态 :

如果 x 处于等待态, Promise 需保持为等待态直至 x 被执行或拒绝。

  const promise1 = new Promise((resolve, reject) => {
    setInterval(() => {
      resolve('已完成')
    }, 3000)
  })
  const promise2 = new Promise((resolve, reject) => resolve(promise1))
  promise2.then(
    (val) => {
      console.log(val); // 3000ms 后输出 已完成
    },
    (val) => {
      console.log(val);
    }
  )

如果 x 处于已完成态,用相同的值执行 Promise

  const promise1 = new Promise((resolve, reject) => resolve('已完成'))
  const promise2 = new Promise((resolve, reject) => resolve(promise1))
  promise2.then(
    (val) => {
      console.log(val); // 输出 已完成
    },
    (val) => {
      console.log(val);
    }
  )

如果 x 处于已拒绝态,用相同的据因拒绝 Promise

  const promise1 = new Promise((resolve, reject) => reject('已拒绝'))
  const promise2 = new Promise((resolve, reject) => resolve(promise1))
  promise2.then(
    (val) => {
      console.log(val);
    },
    (val) => {
      console.log(val);// 输出 已拒绝
    }
  )

如果 x 为对象或者函数

1. 首先尝试执行 x.then

  const promise = new Promise((resolve, reject) => resolve({
    then: () => console.log('hello,promise') //=> hello,promise
  }))
  promise.then((x) => {
    // 首先尝试执行 `x.then` ,输出 hello,promise 。
  })

2. 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 Promise

  const promise = new Promise((resolve, reject) => resolve({
    get then() {
      throw Error("我要拒绝") // error
    }
  }))
  promise.then(
    (val) => {
      console.log(val);
    },
    (val) => {
      console.log(val); //=> error 我要拒绝
    }
  )

3.如果 then 不为函数,以 x 为参数将 Promise 变为已完成状态。

  const promise = new Promise((resolve, reject) => resolve({
    name: 'warbler'
  }))
  promise.then(
    (val) => {
      console.log(val.name); //=>  warbler
    },
    (val) => {
      console.log(val);
    }
  )

4. 如果 x.then 是函数,

x 作为函数的作用域 this 调用。传递两个回调函数作为参数,第一个参数叫做 resolvePromise,第二个参数叫做 rejectPromise

4.1 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)

  const promise = new Promise((resolve, reject) => resolve({
    then: (resolvePromise, rejectPromise) => {
      resolvePromise('已完成')
    }
  }))
  promise.then(
    (val) => {
      console.log(val); //=> 已完成
    },
    (val) => {
      console.log(val);
    }
  )

4.2 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise

  const promise = new Promise((resolve, reject) => resolve({
    then: (resolvePromise, rejectPromise) => {
      rejectPromise('已拒绝')
    }
  }))
  promise.then(
    (val) => {
      console.log(val);
    },
    (val) => {
      console.log(val); //=> 已拒绝
    }
  )

4.3 如果 resolvePromiserejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用

  const promise1 = new Promise((resolve, reject) => resolve({
    then: (resolvePromise, rejectPromise) => {
      resolvePromise('已完成')  // 生效
      resolvePromise('已完成') // 忽略
      rejectPromise('已拒绝') // 忽略
    }
  }))
  promise1.then(
    (val) => {
      console.log(val); //=> 已完成
    },
    (val) => {
      console.log(val);
    }
  )

4.4 如果调用 then 方法抛出了异常 e

如果 resolvePromiserejectPromise 已经被调用,则忽略。

  const promise = new Promise((resolve, reject) => resolve({
    then: (resolvePromise, rejectPromise) => {
      resolvePromise('已完成')
      throw new Error("我要拒绝") // 忽略
    }
  }))
  promise.then(
    (val) => {
      console.log(val); //=> 已完成
    },
    (val) => {
      console.log(val);
    }
  )

否则以 e 为据因拒绝 promise

  const promise = new Promise((resolve, reject) => resolve({
    then: (resolvePromise, rejectPromise) => {
      throw new Error("我要拒绝")
    }
  }))
  promise.then(
    (val) => {
      console.log(val);
    },
    (val) => {
      console.log(val); //=> error 我要拒绝
    }
  )

如果 x 不为对象或者函数,以 x 为参数将 Promise 变为已完成状态。

  const promise = new Promise((resolve, reject) => resolve('warbler'))
  promise.then(
    (val) => {
      console.log(val); //=>  warbler
    },
    (val) => {
      console.log(val);
    }
  )

后语

到这里 Promise/A+ 规范就解析完了,后面的任务就是手写 Promise 了。

参考文献

Promises/A+

promiseA+规范详解

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值