Promise 实现

Promise 是 ES6 新增的语法,解决了回调地狱的问题。

可以把 Promise 看成一个状态机。初始是 pending 状态,可以通过函数 resolvereject ,将状态转变为 resolved 或者 rejected 状态,状态一旦改变就不能再次变化。

then 函数会返回一个 Promise 实例,并且该返回值是一个新的实例而不是之前的实例。因为 Promise 规范规定除了 pending 状态,其他状态是不可以改变的,如果返回的是一个相同实例的话,多个 then 调用就失去意义了。

对于 then 来说,本质上可以把它看成是 flatMap

  1. // 三种状态
  2. const PENDING = "pending";
  3. const RESOLVED = "resolved";
  4. const REJECTED = "rejected";
  5. // promise 接收一个函数参数,该函数会立即执行
  6. function MyPromise(fn) {
  7. let _this = this;
  8. _this.currentState = PENDING;
  9. _this.value = undefined;
  10. // 用于保存 then 中的回调,只有当 promise
  11. // 状态为 pending 时才会缓存,并且每个实例至多缓存一个
  12. _this.resolvedCallbacks = [];
  13. _this.rejectedCallbacks = [];
  14. _this.resolve = function (value) {
  15. if (value instanceof MyPromise) {
  16. // 如果 value 是个 Promise,递归执行
  17. return value.then(_this.resolve, _this.reject)
  18. }
  19. setTimeout(() => { // 异步执行,保证执行顺序
  20. if (_this.currentState === PENDING) {
  21. _this.currentState = RESOLVED;
  22. _this.value = value;
  23. _this.resolvedCallbacks.forEach(cb => cb());
  24. }
  25. })
  26. };
  27. _this.reject = function (reason) {
  28. setTimeout(() => { // 异步执行,保证执行顺序
  29. if (_this.currentState === PENDING) {
  30. _this.currentState = REJECTED;
  31. _this.value = reason;
  32. _this.rejectedCallbacks.forEach(cb => cb());
  33. }
  34. })
  35. }
  36. // 用于解决以下问题
  37. // new Promise(() => throw Error('error))
  38. try {
  39. fn(_this.resolve, _this.reject);
  40. } catch (e) {
  41. _this.reject(e);
  42. }
  43. }
  44. MyPromise.prototype.then = function (onResolved, onRejected) {
  45. var self = this;
  46. // 规范 2.2.7,then 必须返回一个新的 promise
  47. var promise2;
  48. // 规范 2.2.onResolved 和 onRejected 都为可选参数
  49. // 如果类型不是函数需要忽略,同时也实现了透传
  50. // Promise.resolve(4).then().then((value) => console.log(value))
  51. onResolved = typeof onResolved === 'function' ? onResolved : v => v;
  52. onRejected = typeof onRejected === 'function' ? onRejected : r => throw r;
  53. if (self.currentState === RESOLVED) {
  54. return (promise2 = new MyPromise(function (resolve, reject) {
  55. // 规范 2.2.4,保证 onFulfilled,onRjected 异步执行
  56. // 所以用了 setTimeout 包裹下
  57. setTimeout(function () {
  58. try {
  59. var x = onResolved(self.value);
  60. resolutionProcedure(promise2, x, resolve, reject);
  61. } catch (reason) {
  62. reject(reason);
  63. }
  64. });
  65. }));
  66. }
  67. if (self.currentState === REJECTED) {
  68. return (promise2 = new MyPromise(function (resolve, reject) {
  69. setTimeout(function () {
  70. // 异步执行onRejected
  71. try {
  72. var x = onRejected(self.value);
  73. resolutionProcedure(promise2, x, resolve, reject);
  74. } catch (reason) {
  75. reject(reason);
  76. }
  77. });
  78. }));
  79. }
  80. if (self.currentState === PENDING) {
  81. return (promise2 = new MyPromise(function (resolve, reject) {
  82. self.resolvedCallbacks.push(function () {
  83. // 考虑到可能会有报错,所以使用 try/catch 包裹
  84. try {
  85. var x = onResolved(self.value);
  86. resolutionProcedure(promise2, x, resolve, reject);
  87. } catch (r) {
  88. reject(r);
  89. }
  90. });
  91. self.rejectedCallbacks.push(function () {
  92. try {
  93. var x = onRejected(self.value);
  94. resolutionProcedure(promise2, x, resolve, reject);
  95. } catch (r) {
  96. reject(r);
  97. }
  98. });
  99. }));
  100. }
  101. };
  102. // 规范 2.3
  103. function resolutionProcedure(promise2, x, resolve, reject) {
  104. // 规范 2.3.1,x 不能和 promise2 相同,避免循环引用
  105. if (promise2 === x) {
  106. return reject(new TypeError("Error"));
  107. }
  108. // 规范 2.3.2
  109. // 如果 x 为 Promise,状态为 pending 需要继续等待否则执行
  110. if (x instanceof MyPromise) {
  111. if (x.currentState === PENDING) {
  112. x.then(function (value) {
  113. // 再次调用该函数是为了确认 x resolve 的
  114. // 参数是什么类型,如果是基本类型就再次 resolve
  115. // 把值传给下个 then
  116. resolutionProcedure(promise2, value, resolve, reject);
  117. }, reject);
  118. } else {
  119. x.then(resolve, reject);
  120. }
  121. return;
  122. }
  123. // 规范 2.3.3.3.3
  124. // reject 或者 resolve 其中一个执行过得话,忽略其他的
  125. let called = false;
  126. // 规范 2.3.3,判断 x 是否为对象或者函数
  127. if (x !== null && (typeof x === "object" || typeof x === "function")) {
  128. // 规范 2.3.3.2,如果不能取出 then,就 reject
  129. try {
  130. // 规范 2.3.3.1
  131. let then = x.then;
  132. // 如果 then 是函数,调用 x.then
  133. if (typeof then === "function") {
  134. // 规范 2.3.3.3
  135. then.call(
  136. x,
  137. y => {
  138. if (called) return;
  139. called = true;
  140. // 规范 2.3.3.3.1
  141. resolutionProcedure(promise2, y, resolve, reject);
  142. },
  143. e => {
  144. if (called) return;
  145. called = true;
  146. reject(e);
  147. }
  148. );
  149. } else {
  150. // 规范 2.3.3.4
  151. resolve(x);
  152. }
  153. } catch (e) {
  154. if (called) return;
  155. called = true;
  156. reject(e);
  157. }
  158. } else {
  159. // 规范 2.3.4,x 为基本类型
  160. resolve(x);
  161. }
  162. }

以上就是根据 Promise / A+ 规范来实现的代码,可以通过 promises-aplus-tests 的完整测试

Promise 实现 - 图1