Promise 雏形

Promise 构造函数返回一个 promise 对象实例,这个返回的 promise 对象具有一个 then 方法。then 方法中,调用者可以定义两个参数,分别是 onFulfilled 和 onRejected,它们都是函数类型。其中 onFulfilled 通过参数,可以获取 promise 对象 resolved 的值,onRejected 获得 promise 对象 rejected 的值。通过这个值,我们来处理异步完成后的逻辑。

实现

  1. function Promise(executor) {
  2. }
  3. Promise.prototype.then = function(onfulfilled, onrejected) {
  4. }

复习 Promise 的知识,看例子来理解。

  1. let promise1 = new Promise((resolve, reject) => {
  2. resolve("data");
  3. });
  4. promise1.then(data => {
  5. console.log(data);
  6. });
  7. let promise2 = new Promise((resolve, reject) => {
  8. reject("error");
  9. });
  10. promise2.then(data => {
  11. console.log(data);
  12. }, error => {
  13. console.log(error);
  14. });

我们可以得到结论,在使用 new 关键字调用 Promise 构造函数时,在合适的时机(往往是异步结束时),调用 executor 的参数 resolve 方法,并将 resolved 的值作为 resolve 函数参数执行,这个值便可以后续在 then 方法第一个函数参数(onFulfilled)中拿到;同理,在出现错误时,调用 executor 的参数 reject 方法,并将错误信息作为 reject 函数参数执行,这个错误信息可以在后续的 then 方法第二个函数参数(onRejected)中拿到。

因此,我们在实现 Promise 时,应该有一个值用于保存 resolve 或者 reject 的值(因为 Promise 状态的唯一性,所以不需要分别用两个变量分别保存);同时也需要存在一个状态,这个状态就是 Promise 实例的状态(pending、fulfilled、rejected);同时还要提供 resolve 方法以及 reject 方法。

  1. function Promise(executor) {
  2. let self = this;
  3. self.status = "pending";
  4. self.value = null;
  5. self.onResolveCallbacks = [];
  6. self.onRejectCallbacks = [];
  7. function resolve(value) {
  8. if (self.status === "pending") {
  9. self.status = "fulfilled";
  10. self.value = value;
  11. self.onResolveCallbacks.forEach(cb => cb(self.value));
  12. }
  13. }
  14. function reject(reason) {
  15. if (self.status === "pending") {
  16. self.status = "rejected";
  17. self.value = reason;
  18. self.onRejectCallbacks.forEach(cb => cb(self.value));
  19. }
  20. }
  21. try {
  22. executor(resolve, reject);
  23. } catch (e) {
  24. reject(e);
  25. }
  26. }

有一点需要解释的是,执行 executor 有可能会出错就像下面这样,如果出错了 Promise 应该 reject 这个出错的值。所以需要把 executor 放在 try catch 语句。

  1. new Promise(function(resolve, reject) {
  2. throw 2
  3. })

实现 then 方法

  1. Promise.prototype.then = function(onFulfilled, onRejected) {
  2. let self = this
  3. onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
  4. onRejected = typeof onRejected === 'function' ? onRejected : r => {
  5. throw r
  6. }
  7. if (self.status === 'pending') {
  8. self.onResolveCallbacks.push(onFulfilled)
  9. self.onRejectCallbacks.push(onRejected)
  10. }
  11. if (self.status === 'fulfilled') {
  12. onFulfilled(self.value)
  13. }
  14. if (self.status === 'rejected') {
  15. onRejected(self.value)
  16. }
  17. }

为了透传我们在 onFulfilled/onRejected 不是一个函数的时候也默认返回一个函数用于返回当前的 onFulfilled/onRejected 的值,当 status 处于 pending 状态,不能确定调用 onFulfilled 还是onRejected,只有等状态确定后才可以处理,所以把两个 callback 存入回调数组,等到状态确认时调用对应的方法。

实现链式调用

在 Promise A+ 规范中有提到过 then 需要返回一个 Promise 实例,这也是可以链式调用的关键。

改写 then 方法

  1. Promise.prototype.then = function (onFulfilled, onRejected) {
  2. let self = this;
  3. onFulfilled = typeof onFulfilled === "function" ? onFulfilled : v => v;
  4. onRejected = typeof onRejected === "function" ? onRejected : r => {
  5. throw r;
  6. };
  7. let returnedPromise = null;
  8. if (self.status === "pending") {
  9. return returnedPromise = new Promise((resolve, reject) => {
  10. self.onResolveCallbacks.push(onFulfilled);
  11. self.onRejectCallbacks.push(onRejected);
  12. });
  13. }
  14. if (self.status === "fulfilled") {
  15. return returnedPromise = new Promise((resolve, reject) => {
  16. onFulfilled(self.value);
  17. });
  18. }
  19. if (self.status === "rejected") {
  20. return returnedPromise = new Promise((resolve, reject) => {
  21. onRejected(self.value);
  22. });
  23. }
  24. };

根据规范的定义,需要定义一个[Resolve] 解析函数,解析 onFullilled 或 onRejected 的返回值,同时对这两个方法执行期间抛出的错误进行 reject。

  1. // pending
  2. self.onResolveCallbacks.push(() => {
  3. try {
  4. let x = onFulfilled(self.value);
  5. ResolutionProcedure(returnedPromise, x, resolve, reject);
  6. } catch (e) {
  7. reject(e);
  8. }
  9. });
  10. self.onRejectCallbacks.push(() => {
  11. try {
  12. let x = onRejected(self.value);
  13. ResolutionProcedure(returnedPromise, x, resolve, reject);
  14. } catch (e) {
  15. reject(e);
  16. }
  17. });
  18. // fullilled
  19. try {
  20. let x = onFulfilled(self.value);
  21. ResolutionProcedure(returnedPromise, x, resolve, reject);
  22. } catch (e) {
  23. reject(e);
  24. }
  25. // rejected
  26. try {
  27. let x = onRejected(self.value);
  28. ResolutionProcedure(returnedPromise, x, resolve, reject);
  29. } catch (e) {
  30. reject(e);
  31. }

实现 ResolutionProcedure 方法

  1. function ResolutionProcedure(promise, x, resolvePromise, rejectPromise) {
  2. try {
  3. if (promise === x) {
  4. return rejectPromise(new TypeError("2.3.1"));
  5. }
  6. if (x instanceof Promise) {
  7. x.then(
  8. (value) => {
  9. return ResolutionProcedure(promise, value, resolvePromise, rejectPromise);
  10. },
  11. (reason) => {
  12. return rejectPromise(reason);
  13. }
  14. );
  15. }
  16. let called = false;
  17. if (x !== null && (typeof x === "object" || typeof x === "function")) {
  18. try {
  19. let then = x.then;
  20. if (typeof then === "function") {
  21. then.call(x, (value) => {
  22. if (called) return;
  23. called = true;
  24. return ResolutionProcedure(promise, value, resolvePromise, rejectPromise);
  25. }, (reason) => {
  26. if (called) return;
  27. called = true;
  28. return rejectPromise(reason);
  29. });
  30. } else {
  31. return resolvePromise(x);
  32. }
  33. } catch (e) {
  34. if (called) return;
  35. called = true;
  36. return rejectPromise(e);
  37. }
  38. } else {
  39. return resolvePromise(x);
  40. }
  41. } catch (e) {
  42. return rejectPromise(e);
  43. }
  44. }

解释下面这段代码

  1. if (x instanceof Promise) {
  2. x.then(
  3. (value) => {
  4. return ResolutionProcedure(promise, value, resolvePromise, rejectPromise);
  5. },
  6. (reason) => {
  7. return rejectPromise(reason);
  8. }
  9. );
  10. }

为什么 then 的两个参数函数的返回值是不同的?

理解这段代码(原生 Promise)

  1. new Promise((resolve, reject) => {
  2. resolve("resolve");
  3. })
  4. .then(res => {
  5. console.log(res);
  6. return new Promise((resolve, reject) => {
  7. resolve(new Promise((resolve, reject) => {
  8. resolve("inner resolve");
  9. }));
  10. });
  11. }, err => console.log(err))
  12. .then(res => console.log("res", res), err => console.log("err", err));
  13. //////////////////////////////
  14. new Promise((resolve, reject) => {
  15. resolve("resolve");
  16. })
  17. .then(res => {
  18. console.log(res);
  19. return new Promise((resolve, reject) => {
  20. reject(new Promise((resolve, reject) => {
  21. reject("inner resolve");
  22. }));
  23. });
  24. }, err => console.log(err))
  25. .then(res => console.log("res", res), err => console.log("err", err));

两段代码的结果

image.png

image.png

支持异常执行,使用 setTimeout,以 fullilled 为例。

  1. setTimeout(() => {
  2. try {
  3. let x = onFulfilled(self.value);
  4. ResolutionProcedure(returnedPromise, x, resolve, reject);
  5. } catch (e) {
  6. reject(e);
  7. }
  8. }, 0);

完整版

  1. function ResolutionProcedure(promise, x, resolvePromise, rejectPromise) {
  2. try {
  3. if (promise === x) {
  4. return rejectPromise(new TypeError("2.3.1"));
  5. }
  6. if (x instanceof Promise) {
  7. x.then(
  8. (value) => {
  9. return ResolutionProcedure(promise, value, resolvePromise, rejectPromise);
  10. },
  11. (reason) => {
  12. return rejectPromise(reason);
  13. }
  14. );
  15. }
  16. let called = false;
  17. if (x !== null && (typeof x === "object" || typeof x === "function")) {
  18. try {
  19. let then = x.then;
  20. if (typeof then === "function") {
  21. then.call(x, (value) => {
  22. if (called) return;
  23. called = true;
  24. return ResolutionProcedure(promise, value, resolvePromise, rejectPromise);
  25. }, (reason) => {
  26. if (called) return;
  27. called = true;
  28. return rejectPromise(reason);
  29. });
  30. } else {
  31. return resolvePromise(x);
  32. }
  33. } catch (e) {
  34. if (called) return;
  35. called = true;
  36. return rejectPromise(e);
  37. }
  38. } else {
  39. return resolvePromise(x);
  40. }
  41. } catch (e) {
  42. return rejectPromise(e);
  43. }
  44. }
  45. function Promise(executor) {
  46. let self = this;
  47. self.status = "pending";
  48. self.value = null;
  49. self.onResolveCallbacks = [];
  50. self.onRejectCallbacks = [];
  51. function resolve(value) {
  52. if (self.status === "pending") {
  53. self.status = "fulfilled";
  54. self.value = value;
  55. // executor 异步调用 resolve
  56. self.onResolveCallbacks.forEach(cb => cb(self.value));
  57. }
  58. }
  59. function reject(reason) {
  60. if (self.status === "pending") {
  61. self.status = "rejected";
  62. self.value = reason;
  63. // executor 异步调用 reject
  64. self.onRejectCallbacks.forEach(cb => cb(self.value));
  65. }
  66. }
  67. try {
  68. executor(resolve, reject);
  69. } catch (e) {
  70. reject(e);
  71. }
  72. }
  73. Promise.prototype.then = function (onFulfilled, onRejected) {
  74. let self = this;
  75. onFulfilled = typeof onFulfilled === "function" ? onFulfilled : v => v;
  76. onRejected = typeof onRejected === "function" ? onRejected : r => {
  77. throw r;
  78. };
  79. let returnedPromise;
  80. if (self.status === "fulfilled") {
  81. return returnedPromise = new Promise((resolve, reject) => {
  82. setTimeout(() => {
  83. try {
  84. let x = onFulfilled(self.value);
  85. ResolutionProcedure(returnedPromise, x, resolve, reject);
  86. } catch (e) {
  87. reject(e);
  88. }
  89. }, 0);
  90. });
  91. }
  92. if (self.status === "rejected") {
  93. return returnedPromise = new Promise((resolve, reject) => {
  94. setTimeout(() => {
  95. try {
  96. let x = onRejected(self.value);
  97. ResolutionProcedure(returnedPromise, x, resolve, reject);
  98. } catch (e) {
  99. reject(e);
  100. }
  101. }, 0);
  102. });
  103. }
  104. if (self.status === "pending") {
  105. console.log(self.onRejectCallbacks);
  106. return returnedPromise = new Promise((resolve, reject) => {
  107. self.onResolveCallbacks.push(() => {
  108. setTimeout(() => {
  109. try {
  110. let x = onFulfilled(self.value);
  111. ResolutionProcedure(returnedPromise, x, resolve, reject);
  112. } catch (e) {
  113. reject(e);
  114. }
  115. }, 0);
  116. });
  117. self.onRejectCallbacks.push(() => {
  118. setTimeout(() => {
  119. try {
  120. let x = onRejected(self.value);
  121. ResolutionProcedure(returnedPromise, x, resolve, reject);
  122. } catch (e) {
  123. reject(e);
  124. }
  125. }, 0);
  126. });
  127. });
  128. }
  129. };

参考:

[1] 实现一个符合Promise/A+规范的Promise
[2] 前端开发核心知识进阶(gitChat)