前言 Promise 是 ES6 异步编程的核心,很多库的异步都从回调向 Promise 转变,Promise 在前端领域发挥着越来越重要的作用;掌握 Promise 的正确使用、理解 Promise 的实现成为了现代前端开发者不可或缺的技能。
Promise 的核心原理实现 首先我们从 Promise 的定义和使用方式开始分析 Promise。
Promise 的使用分析 Promise 是一个类,在执行这个类的时候,需要传递一个执行器参数,执行器会立即执行。
Promise 的三个状态
pending → 等待
fulfilled → 成功
rejected → 失败
状态切换
pending → fulfilled
pending → rejected
一旦状态发生改变,状态将不可变
执行器中的两个参数,分别是 resolve 和 reject,其实就是两个回调函数,调用 resolve 是从 pending 状态转变为 fulfilled 状态,调用 reject 是从 pending 状态转变为 rejected 状态。传递给这两个回调函数的参数会作为成功或失败的值。
Promise 实例对象具有一个 then 方法,该方法接受两个回调函数,分别来处理成功与失败的状态,then 方法内部会进行判断,然后根据当前的状态调用对应的回调函数。then 方法应该是被定义在原型对象中的。
then 的回调函数中都包含一个值,如果是成功,表示成功后返回的值;如果是失败,就表示失败的原因。
MyPromise 的实现 根据上述分析,我们可以给出如下实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 const PENDING = 'pending' ;const FULFILLED = 'fulfilled' ;const REJECTED = 'rejected' ;class MyPromise { constructor (executor ) { executor (this .resolve , this .reject ); } status = PENDING ; value = undefined ; reason = undefined ; resolve = (value ) => { if (this .status !== PENDING ) return ; this .status = FULFILLED ; this .value = value; }; reject = (reason ) => { if (this .status !== PENDING ) return ; this .status = REJECTED ; this .reason = reason; }; then = (onFulfilled, onRejected ) => { if (this .status === FULFILLED ) { onFulfilled (this .value ); } else if (this .status === REJECTED ) { onRejected (this .reason ); } }; }
接下来我们给出一段验证代码:
验证 resolve
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const MyPromise = require ('./my-promise' );const promise = new MyPromise ((resolve, reject ) => { resolve ('Hello Promise Resolve~' ); }); promise.then ( (value ) => { console .log (value); }, (reason ) => { console .log (reason); } );
验证 reject
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const MyPromise = require ('./my-promise' );const promise = new MyPromise ((resolve, reject ) => { reject ('Hello Promise Reject~' ); }); promise.then ( (value ) => { console .log (value); }, (reason ) => { console .log (reason); } );
验证状态不可变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const MyPromise = require ('./my-promise' );const promise = new MyPromise ((resolve, reject ) => { resolve ('Hello Promise Resolve~' ); reject ('Hello Promise Reject~' ); }); promise.then ( (value ) => { console .log (value); }, (reason ) => { console .log (reason); } );
测试异步
上述简易版 Promise 中如果存在异步操作将无法正确处理
1 2 3 4 5 6 7 8 9 10 11 12 13 const MyPromise = require ('./my-promise' );const promise = new MyPromise ((resole, reject ) => { setTimeout (resolve, 2000 , 'Hello Promise Resolve~' ); }); promise.then ( (value ) => { console .log (value); }, (reason ) => { console .log (reason); } );
上述代码将不会有任何输出
原因分析
MyPromise 的实现中没有考虑异步的实现,在异步函数中修改 Promise 的状态后没有调用 then 回调
then 回调先于 resolve/reject 执行,此时 Promise 的状态还处于 PENDING,将不会执行任何操作[MyPromise 中未对该阶段进行处理]
在 Promise 中加入异步操作 根据 原因分析 给出如下解决办法:
创建 onFulfilled 和 onRejected 两个属性用来存储 then 中的回调
为 then 方法添加状态为 PENDING 的处理逻辑,及时将 onFulfilled 和 onRejected 回调进行存储,便于在异步方法中调用 resolve/reject 变更状态时及时触发对应的 then 中的回调
在成功或失败时及时调用对应的 onFulfilled 或者 onRejected 回调
增加异步操作的 Promise 实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 class MyPromise { constructor (executor ) { executor (this .resolve , this .reject ); } status = PENDING ; value = undefined ; reason = undefined ; onFulfilled = undefined ; onRejected = undefined ; resolve = (value ) => { if (this .status !== PENDING ) return ; this .status = FULFILLED ; this .value = value; this .onFulfilled && this .onFulfilled (this .value ); }; reject = (reason ) => { if (this .status !== PENDING ) return ; this .status = REJECTED ; this .reason = reason; this .onRejected && this .onRejected (this .reason ); }; then = (onFulfilled, onRejected ) => { if (this .status === FULFILLED ) { onFulfilled (this .value ); } else if (this .status === REJECTED ) { onRejected (this .reason ); } else { this .onFulfilled = onFulfilled; this .onRejected = onRejected; } }; }
验证多次 then 调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 const promise = new MyPromise ((resolve ) => { setTimeout (resolve, 2000 , 'Hello Promise Resolve~' ); }); promise.then ( (value ) => { console .log (value + ' first.' ); }, (reason ) => { console .log (reason); } ); promise.then ( (value ) => { console .log (value + ' second.' ); }, (reason ) => { console .log (reason); } ); promise.then ( (value ) => { setTimeout (() => { console .log (value + ' third.' ); }, 1000 ); }, (reason ) => { console .log (reason); } );
原因分析
如果执行器中存在异步逻辑 ,then 函数又先于 异步逻辑 执行,导致多次 then 调用存在覆盖 bug,即在后面的 then 调用会覆盖前面的 then 回调
实现 then 方法的多次调用 根据 原因分析 给出如下解决方案:
将保存 then 回调的 onFulfilled 和 onRejected 属性改为数组形式,便于存储多个 then 回调.
增加存储多次 then 回调的实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 const PENDING = 'pending' ;const FULFILLED = 'fulfilled' ;const REJECTED = 'rejected' ;class MyPromise { constructor (executor ) { executor (this .resolve , this .reject ); } status = PENDING ; value = undefined ; reason = undefined ; onFulfilled = []; onRejected = []; resolve = (value ) => { if (this .status !== PENDING ) { return ; } this .status = FULFILLED ; this .value = value; while (this .onFulfilled .length ) { this .onFulfilled .shift ()(this .value ); } }; reject = (reason ) => { if (this .status !== PENDING ) { return ; } this .status = REJECTED ; this .reason = reason; while (this .onRejected .length ) { this .onRejected .shift ()(this .reason ); } }; then = (onFulfilled, onRejected ) => { if (this .status === FULFILLED ) { onFulfilled (this .value ); } if (this .status === REJECTED ) { onRejected (this .reason ); } if (this .status === PENDING ) { this .onFulfilled .push (onFulfilled); this .onRejected .push (onRejected); } }; }
验证多次 then 调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 const promise = new MyPromise ((resolve ) => { resolve ('Hello Promise Resolve~' ); }); promise.then ( (value ) => { console .log (value + ' first.' ); }, (reason ) => { console .log (reason); } ); promise.then ( (value ) => { console .log (value + ' second.' ); }, (reason ) => { console .log (reason); } ); promise.then ( (value ) => { setTimeout (() => { console .log (value + ' third.' ); }, 1000 ); }, (reason ) => { console .log (reason); } ); const promise = new MyPromise ((resolve ) => { setTimeout (resolve, 2000 , 'Hello Promise Resolve~' ); }); promise.then ( (value ) => { console .log (value + ' first.' ); }, (reason ) => { console .log (reason); } ); promise.then ( (value ) => { console .log (value + ' second.' ); }, (reason ) => { console .log (reason); } ); promise.then ( (value ) => { setTimeout (() => { console .log (value + ' third.' ); }, 1000 ); }, (reason ) => { console .log (reason); } );
实现 then 方法的链式调用[难点] 要想实现 then 的链式调用,主要需要解决两个问题:
返回的是一个新的 MyPromise 的实例;
then 的返回值作为下一次的链式调用的参数。
这里分为两种情况:
直接返回一个值,可以直接作为值使用;
返回一个新的 MyPromise 实例,此时就需要判断其状态;
代码实现 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 const PENDING = 'pending' ;const FULFILLED = 'fulfilled' ;const REJECTED = 'rejected' ;class MyPromise { constructor (executor ) { executor (this .resolve , this .reject ); } status = PENDING ; value = undefined ; reason = undefined ; onFulfilled = []; onRejected = []; resolve = (value ) => { if (this .status !== PENDING ) { return ; } this .status = FULFILLED ; this .value = value; while (this .onFulfilled .length ) { this .onFulfilled .shift ()(this .value ); } }; reject = (reason ) => { if (this .status !== PENDING ) { return ; } this .status = REJECTED ; this .reason = reason; while (this .onRejected .length ) { this .onRejected .shift ()(this .reason ); } }; then = (onFulfilled, onRejected ) => { return new MyPromise ((resolve, reject ) => { if (this .status === FULFILLED ) { const result = onFulfilled (this .value ); resolvePromise (result, resolve, reject); } if (this .status === REJECTED ) { onRejected (this .reason ); } if (this .status === PENDING ) { this .onFulfilled .push (onFulfilled); this .onRejected .push (onRejected); } }); }; } function resolvePromise (result, resolve, reject ) { if (result instanceof MyPromise ) { result.then (resolve, reject); } else { resolve (result); } }
验证链式调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 const promise1 = new MyPromise ((resolve ) => { resolve ('Hello Promise Resolve~' ); }); const promise2 = promise1.then ( (value ) => { console .log (value + ' promise1.' ); return 'Hello Promise2 Resolve~' ; }, (reason ) => { console .log (reason); } ); promise2.then ( (value ) => { console .log (value + ` promise2.` ); }, (reason ) => { console .log (reason + ` promise2.` ); } );
then 方法链式调用识别 Promise 对象自返回 [难点] 在 Promise 中,如果 then 方法返回的是自己的 Promise 对象,则会发生 Promise 的嵌套,这个时候程序会报错。
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 const p1 = new Promise ((resolve, reject ) => { resolve (12 ); }); const p2 = p1.then ((v ) => { console .log (v); return p2; }); p2.then ((v ) => console .log (v));
解决办法
只需判断 then 返回的 Promise 实例与 then 中回调函数返回的实例是否是同一个即可,如果是引用的同一个实例,那么就抛出错误
实现代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 const PENDING = 'pending' ;const FULFILLED = 'fulfilled' ;const REJECTED = 'rejected' ;class MyPromise { constructor (executor ) { executor (this .resolve , this .reject ); } status = PENDING ; value = undefined ; reason = undefined ; onFulfilled = []; onRejected = []; resolve = (value ) => { if (this .status !== PENDING ) { return ; } this .status = FULFILLED ; this .value = value; while (this .onFulfilled .length ) { this .onFulfilled .shift ()(this .value ); } }; reject = (reason ) => { if (this .status !== PENDING ) { return ; } this .status = REJECTED ; this .reason = reason; while (this .onRejected .length ) { this .onRejected .shift ()(this .reason ); } }; then = (onFulfilled, onRejected ) => { const promise = new MyPromise ((resolve, reject ) => { if (this .status === FULFILLED ) { setTimeout (() => { const result = onFulfilled (this .value ); resolvePromise (promise, result, resolve, reject); }, 0 ); } if (this .status === REJECTED ) { onRejected (this .reason ); } if (this .status === PENDING ) { this .onFulfilled .push (onFulfilled); this .onRejected .push (onRejected); } }); return promise; }; } function resolvePromise (promise, result, resolve, reject ) { if (promise === result) { return reject ( new TypeError ('Chaining cycle detected for promise #<Promise>' ) ); } else { if (result instanceof MyPromise ) { result.then (resolve, reject); } else { resolve (result); } } }
这里 then 方法中的 setTimeout 的作用并不是延迟执行,而是为了调用 resolvePromise 函数时,保证创建的 promise 存在。
验证代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 const promise1 = new MyPromise ((resolve ) => { resolve ('Hello Promise Resolve~' ); }); const promise2 = promise1.then ( (value ) => { console .log (value + ' promise1.' ); return promise2; }, (reason ) => { console .log (reason); } ); promise2.then ( (value ) => { console .log (value + ` promise2.` ); }, (reason ) => { console .log (reason + ` promise2.` ); } );
捕捉错误及 then 链式调用其他状态代码补充 到目前为止我们实现的 Promise 并没有对异常做任何处理,为了保证代码的健壮性,我们需要对异常做一些处理。
捕捉执行器报错 如果执行器函数在执行过程中发生了异常,需要捕获异常并且在捕获逻辑中调用 reject 将异常传出去
关键实现代码
1 2 3 4 5 6 7 constructor (executor ) { try { executor (this .resolve , this .reject ); } catch (error) { this .reject (error); } }
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const promise1 = new MyPromise ((resolve ) => { throw new Error ('执行器异常' ); }); promise1.then (console .log , console .log );
捕捉 then 中的报错 如果需要捕获 then 中的异常,与执行器中同理,需要在 then 中将捕获到的异常通过 reject 传递出去,异常需要通过 try...catch 捕获。
关键实现代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 then = (onFulfilled, onRejected ) => { const promise = new MyPromise ((resolve, reject ) => { if (this .status === FULFILLED ) { setTimeout (() => { try { const result = onFulfilled (this .value ); resolvePromise (promise, result, resolve, reject); } catch (error) { reject (error); } }, 0 ); } if (this .status === REJECTED ) { onRejected (this .reason ); } if (this .status === PENDING ) { this .onFulfilled .push (onFulfilled); this .onRejected .push (onRejected); } }); return promise; };
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 const promise1 = new MyPromise ((resolve ) => { resolve (Math .PI ); }); promise1 .then ((pi ) => console .log (2 * pi * r), console .log ) .then (console .log , console .log );
错误与异步状态的链式调用 目前只对成功状态的 then 进行了链式调用以及错误处理,错误与异步状态未进行处理,参照成功状态下的错误处理进行实现
关键实现代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 then = (onFulfilled, onRejected ) => { const promise = new MyPromise ((resolve, reject ) => { if (this .status === FULFILLED ) { setTimeout (() => { try { const result = onFulfilled (this .value ); resolvePromise (promise, result, resolve, reject); } catch (error) { reject (error); } }, 0 ); } if (this .status === REJECTED ) { setTimeout (() => { try { const result = onRejected (this .reason ); resolvePromise (promise, result, resolve, reject); } catch (error) { reject (error); } }, 0 ); } if (this .status === PENDING ) { this .onFulfilled .push ((value ) => { setTimeout (() => { try { const result = onFulfilled (value); resolvePromise (promise, result, resolve, reject); } catch (error) { reject (error); } }, 0 ); }); this .onRejected .push ((reason ) => { setTimeout (() => { try { const result = onRejected (reason); resolvePromise (promise, result, resolve, reject); } catch (error) { reject (error); } }, 0 ); }); } }); return promise; };
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const MyPromise = require ('./myPromise' );let promise = new MyPromise ((resolve, reject ) => { setTimeout (resolve, 2000 , '成功' ); }); promise .then ((value ) => { console .log ('resolve' , value); throw new Error ('then的执行过程中遇到异常' ); }) .then (null , (reason ) => { console .log (reason.message ); });
将 then 方法的参数变成可选参数 Promise 中的 then 方法其实是两个可选参数 ,如果我们不传递任何参数的话,里面的结果是向下传递的,直到捕获为止。
示例代码
1 2 3 4 5 6 7 8 new Promise ((resolve, reject ) => { resolve (100 ); }) .then () .then () .then () .then ((value ) => console .log (value));
这段代码可以理解为
1 2 3 4 5 6 7 new Promise ((resolve, reject ) => { resolve (100 ); }) .then ((value ) => value) .then ((value ) => value) .then ((value ) => value) .then ((value ) => console .log (value));
关键实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 then (onFulfilled, onRejected) { onFulfilled = onFulfilled ? onFulfilled : value => value onRejected = onRejected ? onRejected : reason => { throw reason } const promise = new MyPromise ((resolve, reject ) => { if (this .status === FULFILLED ) {... } else if (this .status === REJECTED ) {... } else {... } }) return promise }
Promise.all 方法的实现 简单的说 Promise.all() 会将多个 Promise 实例包装为一个 Promise 实例,且顺序与调用顺序一致:示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function p1 ( ) { return new Promise ((resolve, reject ) => { setTimeout (() => { resolve ('p1' ); }, 2000 ); }); } function p2 ( ) { return new Promise ((resolve, reject ) => { setTimeout (() => { resolve ('p2' ); }, 0 ); }); } Promise .all (['a' , 'b' , p1 (), p2 (), 'c' ]).then ((result ) => { console .log (result); });
在这段代码中,我们的 p1 的执行是延迟了 2s 的,这里如果不使用 Promise.all()的话最终顺序是与我们调用不同的。
分析 Promise.all 的实现思路
all() 方法是通过类直接调用的,所以是一个静态方法
all() 方法接收一个数组,数组中的值可以是一个普通值,也可以是一个 MyPromise 实例
return 一个新的 MyPromise 实例
遍历数组中的每一个值,判断值的类型,如果是一个普通值就直接将值存入一个结果数组;如果是一个 MyPromise 实例对象,会调用其 then 方法,然后根据执行后的状态,如果失败的话调用 MyPromise 的 reject 方法,如果成功的话将值存入结果数组;
存入数组时计数,如果存入的数量达到传入的数组长度,说明调用完毕,执行 resolve 并将最终的结果数组作为参数返回。
关键实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 MyPromise .all = (array ) => { let result = []; let count = 0 ; return new MyPromise ((resolve, reject ) => { function addResult (result, index, value, resolve ) { result[index] = value; if (++count === array.length ) { resolve (result); } } array.forEach ((item, index ) => { if (item instanceof MyPromise ) { item.then ( (value ) => { addResult (result, index, value, resolve); }, (reason ) => { reject (reason); } ); } else { addResult (result, index, item, resolve); } }); }); };
测试示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function p1 ( ) { return new MyPromise ((resolve, reject ) => { setTimeout (() => { resolve ('p1' ); }, 2000 ); }); } function p2 ( ) { return new MyPromise ((resolve, reject ) => { setTimeout (() => { resolve ('p2' ); }, 0 ); }); } MyPromise .all (['a' , 'b' , p1 (), p2 (), 'c' ]).then ((result ) => { console .log (result); });
Promise.resolve 方法的实现 关于 Promise.resolve()方法的用法可以参考 Promise.resolve()与 Promise.reject()。直线思路分析
该方法是一个静态方法
该方法接收的如果是一个值就直接将该值包装为一个 MyPromise 实例对象返回,如果是一个 MyPromise 实例对象,则直接返回
关键实现
1 2 3 4 5 6 7 8 9 MyPromise .resolve = (value ) => { if (value instanceof MyPromise ) { return value; } else { return new MyPromise ((resolve ) => resolve (value)); } };
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function p1 ( ) { return new MyPromise ((resolve, reject ) => { reject ('p1' ); }); } function p2 ( ) { return new MyPromise ((resolve, reject ) => { setTimeout (() => { resolve ('p2' ); }, 2000 ); }); } MyPromise .resolve (p1 ()).then (console .log , console .log );MyPromise .resolve (3.1415926 ).then (console .log );MyPromise .resolve (p2 ()).then (console .log , console .log );
finally 方法的实现 实现思路分析
不管 Promise 是 Fulfilled 还是 Rejected 状态,都会调用 finally 函数中的回调参数
返回一个新的 Promise 实例
关键实现
1 2 3 4 5 6 finally (callback ) { return this .then ( value => new MyPromise .resolve (callback ()).then (() => value), reason => new MyPromise .resolve (callback ()).then (() => { throw reason }) ); }
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 function p1 ( ) { return new MyPromise ((resolve, reject ) => { setTimeout (() => { resolve ('p1' ); }, 2000 ); }); } function p2 ( ) { return new MyPromise ((resolve, reject ) => { reject ('p2 reject' ); }); } p2 () .finally (() => { console .log ('finally p2' ); return p1 (); }) .then ( (value ) => { console .log (value); }, (reason ) => { console .log (reason); } );
catch 方法的实现 关于 catch 方法可以参考 catch(),实现该方法其实非常简单,只需要在内部调用 then 方法,不传递第一个回调函数即可
关键实现
1 2 3 catch (callback) { return this .then (null , callback); }
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 function p ( ) { return new MyPromise ((resolve, reject ) => { reject (new Error ('reject' )); }); } p () .then ((value ) => { console .log (value); }) .catch ((reason ) => console .log (reason));
完整代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 const PENDING = 'pending' ;const FULFILLED = 'fulfilled' ;const REJECTED = 'rejected' ;class MyPromise { constructor (executor ) { try { executor (this .resolve , this .reject ); } catch (error) { this .reject (error); } } status = PENDING ; value = undefined ; reason = undefined ; onFulfilled = []; onRejected = []; resolve = (value ) => { if (this .status !== PENDING ) { return ; } this .status = FULFILLED ; this .value = value; while (this .onFulfilled .length ) { this .onFulfilled .shift ()(this .value ); } }; reject = (reason ) => { if (this .status !== PENDING ) { return ; } this .status = REJECTED ; this .reason = reason; while (this .onRejected .length ) { this .onRejected .shift ()(this .reason ); } }; then = (onFulfilled, onRejected ) => { onFulfilled = onFulfilled ? onFulfilled : (value ) => value; onRejected = onRejected ? onRejected : (reason ) => { throw reason; }; const promise = new MyPromise ((resolve, reject ) => { if (this .status === FULFILLED ) { setTimeout (() => { try { const result = onFulfilled (this .value ); resolvePromise (promise, result, resolve, reject); } catch (error) { reject (error); } }, 0 ); } if (this .status === REJECTED ) { setTimeout (() => { try { const result = onRejected (this .reason ); resolvePromise (promise, result, resolve, reject); } catch (error) { reject (error); } }, 0 ); } if (this .status === PENDING ) { this .onFulfilled .push ((value ) => { setTimeout (() => { try { const result = onFulfilled (value); resolvePromise (promise, result, resolve, reject); } catch (error) { reject (error); } }, 0 ); }); this .onRejected .push ((reason ) => { setTimeout (() => { try { const result = onRejected (reason); resolvePromise (promise, result, resolve, reject); } catch (error) { reject (error); } }, 0 ); }); } }); return promise; }; finally (callback ) { return this .then ( (value ) => new MyPromise .resolve (callback ()).then (() => value), (reason ) => new MyPromise .resolve (callback ()).then (() => { throw reason; }) ); } catch (callback) { return this .then (null , callback); } static all (array ) { let result = []; let count = 0 ; return new MyPromise ((resolve, reject ) => { function addResult (result, index, value, resolve ) { result[index] = value; if (++count === array.length ) { resolve (result); } } array.forEach ((item, index ) => { if (item instanceof MyPromise ) { item.then ( (value ) => { addResult (result, index, value, resolve); }, (reason ) => { reject (reason); } ); } else { addResult (result, index, item, resolve); } }); }); } static resolve (value ) { if (value instanceof MyPromise ) { return value; } else { return new MyPromise ((resolve ) => resolve (value)); } } } function resolvePromise (promise, result, resolve, reject ) { if (promise === result) { return reject ( new TypeError ('Chaining cycle detected for promise #<Promise>' ) ); } else { if (result instanceof MyPromise ) { result.then (resolve, reject); } else { resolve (result); } } }