学习链接

BAT前端经典面试问题:史上最最最详细的手写Promise教程(代码来源,其他链接是为了当收藏家(

这篇手写 Promise 你一定要康康

【JavaScript】必须要会的手写Promise

看了就会,手写Promise原理,最通俗易懂的版本!!!

面试官:“你能手写一个 Promise 吗”

手把手一行一行代码教你“手写Promise“,完美通过 Promises/A+ 官方872个测试用例

实现 Promise

Promise

  1. class Promise {
  2. constructor(executor) {
  3. this.state = 'pending';
  4. this.value = undefined;
  5. this.reason = undefined;
  6. this.onResolvedCallback = [];
  7. this.onRejectedCallback = [];
  8. const resolve = value => {
  9. if (this.state === 'pending') {
  10. this.state = 'fulfilled';
  11. this.value = value;
  12. this.onResolvedCallback.forEach(fn => fn());
  13. }
  14. };
  15. const reject = reason => {
  16. if (this.state === 'pending') {
  17. this.state = 'rejected';
  18. this.reason = reason;
  19. this.onRejectedCallback.forEach(fn => fn());
  20. }
  21. };
  22. try {
  23. executor(resolve, reject);
  24. } catch (err) {
  25. reject(err);
  26. }
  27. }
  28. then(onFulfilled, onRejected) {
  29. onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
  30. onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err; };
  31. const promise2 = new Promise((resolve, reject) => {
  32. if (this.state === 'fulfilled') {
  33. queueMicrotask(() => {
  34. try {
  35. let result = onFulfilled(this.value);
  36. resolvePromise(promise2, result, resolve, reject);
  37. } catch (error) {
  38. reject(error);
  39. }
  40. });
  41. }
  42. if (this.state === 'rejected') {
  43. queueMicrotask(() => {
  44. try {
  45. let result = onRejected(this.reason);
  46. resolvePromise(promise2, result, resolve, reject);
  47. } catch (error) {
  48. reject(error);
  49. }
  50. });
  51. }
  52. if (this.state === 'pending') {
  53. this.onResolvedCallback.push(() => {
  54. queueMicrotask(() => {
  55. try {
  56. let result = onFulfilled(this.value);
  57. resolvePromise(promise2, result, resolve, reject);
  58. } catch (error) {
  59. reject(error);
  60. }
  61. });
  62. });
  63. this.onRejectedCallback.push(() => {
  64. queueMicrotask(() => {
  65. try {
  66. let result = onRejected(this.reason);
  67. resolvePromise(promise2, result, resolve, reject);
  68. } catch (error) {
  69. reject(error);
  70. }
  71. });
  72. });
  73. }
  74. })
  75. return promise2; // 完成链式调用
  76. }
  77. }
  78. function resolvePromise(promise2, result, resolve, reject) {
  79. // resolve 和 reject 是 promise2 实例构建时候的参数方法
  80. // result 是then方法参数中传入的回调函数 的返回结果
  81. if (result === promise2) {
  82. return reject(new TypeError('Chaining cycle detected for promise'));
  83. }
  84. // 防止 resolve reject 被多次调用(catch)
  85. let called = false;
  86. if (result === null || (typeof result !== 'object' && typeof result !== 'function')) {
  87. return resolve(result);
  88. }
  89. try {
  90. let then = result.then;
  91. if (typeof then !== 'function') {
  92. return resolve(result);
  93. }
  94. then.call(result, value => {
  95. if (called) return;
  96. called = true;
  97. resolvePromise(promise2, value, resolve, reject);
  98. }, reason => {
  99. if (called) return;
  100. called = true;
  101. reject(reason);
  102. })
  103. } catch (error) {
  104. if (called) return;
  105. called = true;
  106. reject(error);
  107. }
  108. }
  109. Promise.resolve = function (value) {
  110. return new Promise((resolve, reject) => {
  111. resolve(value);
  112. });
  113. }
  114. Promise.reject = function (reason) {
  115. return new Promise((resolve, reject) => {
  116. reject(reason);
  117. });
  118. }
  119. Promise.all = promiseArr => {
  120. return new Promise((resolve, reject) => {
  121. if (!promiseArr[Symbol.iterator]) {
  122. throw new TypeError(`${promiseArr} is not iterable`) // 需要iterator接口
  123. }
  124. if (!Array.isArray(promiseArr)) {
  125. promiseArr = Array.from(promiseArr); // 根据 iterator 接口转为数组
  126. }
  127. let result = [], count = 0; // count 记录fulfilled数量
  128. promiseArr.forEach((p, i) => {
  129. Promise.resolve(p).then(res => { // 转为 Promise 对象
  130. count++; // 进入then的回调, fulfilled的实例数加一
  131. result[i] = res;
  132. if (count === promiseArr.length) {
  133. resolve(result);
  134. }
  135. }, err => {
  136. reject(err);
  137. })
  138. })
  139. })
  140. }
  141. Promise.any = promiseArr => {
  142. return new Promise((resolve, reject) => {
  143. if (!promiseArr[Symbol.iterator]) {
  144. throw new TypeError(`${promiseArr}is not iterable`);
  145. }
  146. if (!Array.isArray(promiseArr)) {
  147. promiseArr = Array.from(promiseArr);
  148. }
  149. const result = [];
  150. let count = 0;
  151. promiseArr.forEach((p, i) => {
  152. Promise.resolve(p).then(
  153. value => {
  154. resolve(value);
  155. },
  156. reason => {
  157. count++;
  158. result[i] = reason;
  159. if (count === promiseArr.length) {
  160. reject(new AggregateError(result, 'All Promises were rejected'));
  161. }
  162. }
  163. )
  164. });
  165. })
  166. }
  167. Promise.race = promiseArr => {
  168. return new Promise((resolve, reject) => {
  169. if (!promiseArr[Symbol.iterator]) {
  170. throw new TypeError(`${promiseArr} is not iterable`);
  171. }
  172. if (!Array.isArray(promiseArr)) {
  173. Array.from(promiseArr);
  174. }
  175. promiseArr.forEach(element => {
  176. Promise.resolve(element).then(resolve, reject);
  177. });
  178. });
  179. };
  180. Promise.allSettled = promiseArr => {
  181. return new Promise((resolve, reject) => {
  182. if (!promiseArr[Symbol.iterator]) {
  183. throw new TypeError(`${promiseArr} is not iterable`);
  184. }
  185. if (!Array.isArray(promiseArr)) {
  186. promiseArr = Array.from(promiseArr);
  187. }
  188. const resArr = [];
  189. let count = 0;
  190. promiseArr.forEach((element, index) => {
  191. Promise.resolve(element).then(
  192. valule => {
  193. resArr[index] = {
  194. status: 'fulfilled',
  195. valule
  196. }
  197. count++;
  198. if (count === promiseArr.length) resolve(resArr);
  199. },
  200. reason => {
  201. resArr[index] = {
  202. status: 'rejected',
  203. reason
  204. }
  205. count++;
  206. if (count === promiseArr.length) resolve(resArr);
  207. }
  208. );
  209. });
  210. })
  211. };
  212. Promise.prototype.finally = callback => {
  213. return this.then(
  214. value => Promise.resolve(callback()).then(() => value),
  215. reason => Promise.resolve(callback()).then(() => { throw reason; })
  216. )
  217. };