1、Promise规范解读

1、如果x和promise 都指向同一个对象,则以typeError为reason 拒绝执行promise。
2、如果x 是Promise对象,则promise采用x当前的状态:

a. 如果x是pending状态,promise必须保持pending状态直到x的状态变为resolved或者rejected。
b. 如果x是resolved状态,用相同的值value执行promise。
c. 如果x是rejected状态,则用相同的原因reason执行promise。

3、如果x是一个对象或者函数:

a. 将promise的then方法指向x.then。
b. 如果x.then属性抛出异常error,则以error为reason来调用reject。
c. 如果then是是一个函数,那么用x为this来调用它,第一个参数为 resolvePromise,第二个参数为rejectPromise
ⅰ. 如果resolvePromise以值y为参数被调用,则运行 [Resolve]
ⅱ. 如果 rejectPromise 以据因 r 为参数被调用,则用原因r执行promise(reject)。
ⅲ. 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则使用第一次调用并忽略剩下的调用。
ⅳ. 如果then抛出了异常 error

4、如果 resolvePromise 或 rejectPromise 已经被调用,则忽略它。
5、否则用error为reason拒绝promise

d. 如果then不是function,用x为参数执行promise

6、如果x不是一个object或者function,用x为参数执行promise。

2、实现

构造函数修改:

  1. function CutePromise(executor) {
  2. // value 记录异步任务成功的执行结果
  3. this.value = null;
  4. // reason 记录异步任务失败的原因
  5. this.reason = null;
  6. // status 记录当前状态,初始化是 pending
  7. this.status = 'pending';
  8. // 缓存两个队列,维护 resolved 和 rejected 各自对应的处理函数
  9. this.onResolvedQueue = [];
  10. this.onRejectedQueue = [];
  11. // 把 this 存下来,后面会用到
  12. var self = this;
  13. // 定义 resolve 函数
  14. function resolve(value) {
  15. // 如果是 pending 状态,直接返回
  16. if (self.status !== 'pending') {
  17. return;
  18. }
  19. // 异步任务成功,把结果赋值给 value
  20. self.value = value;
  21. // 当前状态切换为 resolved
  22. self.status = 'resolved';
  23. // 批量执行 resolved 队列里的任务
  24. self.onResolvedQueue.forEach(resolved => resolved(self.value));
  25. }
  26. // 定义 reject 函数
  27. function reject(reason) {
  28. // 如果是 pending 状态,直接返回
  29. if (self.status !== 'pending') {
  30. return;
  31. }
  32. // 异步任务失败,把结果赋值给 value
  33. self.reason = reason;
  34. // 当前状态切换为 rejected
  35. self.status = 'rejected';
  36. // 用 setTimeout 延迟队列任务的执行
  37. // 批量执行 rejected 队列里的任务
  38. self.onRejectedQueue.forEach(rejected => rejected(self.reason));
  39. }
  40. // 把 resolve 和 reject 能力赋予执行器
  41. try{
  42. execute(resolve, reject)
  43. }catch(e){
  44. reject(e)
  45. }
  46. }

then方法:

  1. // then 方法接收两个函数作为入参(可选)
  2. CutePromise.prototype.then = function(onResolved, onRejected) {
  3. // 注意,onResolved 和 onRejected必须是函数;如果不是,我们此处用一个透传来兜底
  4. if (typeof onResolved !== 'function') {
  5. onResolved = function(x) {return x};
  6. }
  7. if (typeof onRejected !== 'function') {
  8. onRejected = function(e) {throw e};
  9. }
  10. // 依然是保存 this
  11. var self = this;
  12. // 这个变量用来存返回值 x
  13. let x
  14. // resolve态的处理函数
  15. function resolveByStatus(resolve, reject) {
  16. // 包装成异步任务,确保决议程序在 then 后执行
  17. setTimeout(function() {
  18. try {
  19. // 返回值赋值给 x
  20. x = onResolved(self.value);
  21. // 进入决议程序
  22. resolutionProcedure(promise2, x, resolve, reject);
  23. } catch (e) {
  24. // 如果onResolved或者onRejected抛出异常error,则promise2必须被rejected,用error做reason
  25. reject(e);
  26. }
  27. });
  28. }
  29. // reject态的处理函数
  30. function rejectByStatus(resolve, reject) {
  31. // 包装成异步任务,确保决议程序在 then 后执行
  32. setTimeout(function() {
  33. try {
  34. // 返回值赋值给 x
  35. x = onRejected(self.reason);
  36. // 进入决议程序
  37. resolutionProcedure(promise2, x, resolve, reject);
  38. } catch (e) {
  39. reject(e);
  40. }
  41. });
  42. }
  43. // 注意,这里我们不能再简单粗暴 return this 了,需要 return 一个符合规范的 Promise 对象
  44. var promise2 = new CutePromise(function(resolve, reject) {
  45. // 判断状态,分配对应的处理函数
  46. if (self.status === 'resolved') {
  47. // resolve 处理函数
  48. resolveByStatus(resolve, reject);
  49. } else if (self.status === 'rejected') {
  50. // reject 处理函数
  51. rejectByStatus(resolve, reject);
  52. } else if (self.status === 'pending') {
  53. // 若是 pending ,则将任务推入对应队列
  54. self.onResolvedQueue.push(function() {
  55. resolveByStatus(resolve, reject);
  56. });
  57. self.onRejectedQueue.push(function() {
  58. rejectByStatus(resolve, reject);
  59. });
  60. }
  61. });
  62. // 把包装好的 promise2 return 掉
  63. return promise2;
  64. };

resolutionProcedure是关键:

  1. function resolutionProcedure(promise2, x, resolve, reject) {
  2. // 这里 hasCalled 这个标识,是为了确保 resolve、reject 不要被重复执行
  3. let hasCalled;
  4. if (x === promise2) {
  5. // 决议程序规范:如果 resolve 结果和 promise2相同则reject,这是为了避免死循环
  6. return reject(new TypeError('为避免死循环,此处抛错'));
  7. } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
  8. // 决议程序规范:如果x是一个对象或者函数,则需要额外处理下
  9. try {
  10. // 首先是看它有没有 then 方法(是不是 thenable 对象)
  11. let then = x.then;
  12. // 如果是 thenable 对象,则将promise的then方法指向x.then。
  13. if (typeof then === 'function') {
  14. // 如果 then 是是一个函数,那么用x为this来调用它,第一个参数为 resolvePromise,第二个参数为rejectPromise
  15. then.call(x, y => {
  16. // 如果已经被 resolve/reject 过了,那么直接 return
  17. if (hasCalled) return;
  18. hasCalled = true;
  19. // 进入决议程序(递归调用自身)
  20. resolutionProcedure(promise2, y, resolve, reject);
  21. }, err => {
  22. // 这里 hascalled 用法和上面意思一样
  23. if (hasCalled) return;
  24. hasCalled = true;
  25. reject(err);
  26. });
  27. } else {
  28. // 如果then不是function,用x为参数执行promise
  29. resolve(x);
  30. }
  31. } catch (e) {
  32. if (hasCalled) return;
  33. hasCalled = true;
  34. reject(e);
  35. }
  36. } else {
  37. // 如果x不是一个object或者function,用x为参数执行promise
  38. resolve(x);
  39. }
  40. }