手写系列一 实现了一个基础版的Promise:
1 2 3 4 5 6 7 8 const ps = new Pms ((resolve, reject ) => { setTimeout (() => { resolve ('success resolve' ) }, 1000 ) }) ps.then ((res ) => { console .log (res) })
但该版本还有缺陷,比如不支持链式调用。 想想链式调用的原理,一个then后面接一个then,那说明每个then都需要return new Promise(),这样下一个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 function then (onFulfilled, onRejected ) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value ) => value onRejected = typeof onRejected === 'function' ? onRejected : (reason ) => { throw reason } let promise2 = new MyPromise ((resolve, reject ) => { if (this .status === FULFILLED ) { setTimeout (() => { try { let x = onFulfilled (this .value ) resolvePromise (promise2, x, resolve, reject) } catch (e) { reject (e) } }, 0 ) } if (this .status === REJECTED ) { setTimeout (() => { try { let x = onRejected (this .reason ) resolvePromise (promise2, x, resolve, reject) } catch (e) { reject (e) } }, 0 ) } if (this .status === PENDING ) { this .onFulfilledCallbacks .push (() => { setTimeout (() => { try { let x = onFulfilled (this .value ) resolvePromise (promise2, x, resolve, reject) } catch (e) { reject (e) } }) }) this .onRejectedCallbacks .push (() => { setTimeout (() => { try { let x = onRejected (this .reason ) resolvePromise (promise2, x, resolve, reject) } catch (e) { reject (e) } }) }) } }) return promise2 }
接下来需要实现resolvePromise函数:
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 function resolvePromise (promise2, x, resolve, reject ) { if (x === promise2) { return reject ( new TypeError ('Chaining cycle detected for promise #<MyPromise>' ) ) } let called = false if ((typeof x === 'object' && x !== null ) || typeof x === 'function' ) { let then = x.then try { if (typeof then === 'function' ) { then.call ( x, (y ) => { if (called) return called = true resolvePromise (promise2, y, resolve, reject) }, (r ) => { if (called) return called = true reject (r) } ) } else { resolve (x) } } catch (e) { if (called) return called = true reject (e) } } else { resolve (x) } }
if (x === promise2)的作用是:如果这个promise与返回值x相等,则需要reject这个类型错误(PromiseA+规范所写)。 if ((typeof x === ‘object’ && x !== null) || typeof x === ‘function’):如果x不是一个对象或者函数,那么为普通值直接resolve出去即可。 接下来的判断是:如果then是一个函数则认为x是一个promise对象,然后调用它。并且附带2个参数(函数)处理resolve(参数y)和reject(参数r),如果r和y被多次调用或者对某个函数重复调用,第一次调用优先,其他忽略,因此指定一个全局变量called来控制调用。 如果调用后抛出异常,这个异常可能在调用y或者r函数后造成也可能是在之前就抛出的 因此也需要使用called来控制是否抛出异常。而如果then不是一个函数或者对象,那么确定fulfilled状态resolve出去即可
至此,就可以正常进行链式调用了:
1 2 3 4 5 6 7 8 9 new Pms ((resolve, reject ) => { resolve ('success' ) }) .then ((res ) => { console .log (res) }) .then ((res ) => { console .log (res) })
完整实现:
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 const [PENDING , FULFILLED , REJECTED ] = ['PENDING' , 'FULFILLED' , 'REJECTED' ]class MyPromise { constructor (executor ) { this .status = PENDING this .value = undefined this .reason = undefined this .onFulfilledCallbacks = [] this .onRejectedCallbacks = [] const resolve = (value ) => { if (value instanceof MyPromise ) { value.then (resolve, reject) return } if (this .status === PENDING ) { this .status = FULFILLED this .value = value this .onFulfilledCallbacks .forEach ((fn ) => fn ()) } } const reject = (reason ) => { if (this .status === PENDING ) { this .status = REJECTED this .reason = reason this .onRejectedCallbacks .forEach ((fn ) => fn ()) } } try { executor (resolve, reject) } catch (e) { reject (e) } } then (onFulfilled, onRejected ) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value ) => value onRejected = typeof onRejected === 'function' ? onRejected : (reason ) => { throw reason } let promise2 = new MyPromise ((resolve, reject ) => { if (this .status === FULFILLED ) { setTimeout (() => { try { let x = onFulfilled (this .value ) resolvePromise (promise2, x, resolve, reject) } catch (e) { reject (e) } }, 0 ) } if (this .status === REJECTED ) { setTimeout (() => { try { let x = onRejected (this .reason ) resolvePromise (promise2, x, resolve, reject) } catch (e) { reject (e) } }, 0 ) } if (this .status === PENDING ) { this .onFulfilledCallbacks .push (() => { setTimeout (() => { try { let x = onFulfilled (this .value ) resolvePromise (promise2, x, resolve, reject) } catch (e) { reject (e) } }) }) this .onRejectedCallbacks .push (() => { setTimeout (() => { try { let x = onRejected (this .reason ) resolvePromise (promise2, x, resolve, reject) } catch (e) { reject (e) } }) }) } }) return promise2 } } function resolvePromise (promise2, x, resolve, reject ) { if (x === promise2) { return reject ( new TypeError ('Chaining cycle detected for promise #<MyPromise>' ) ) } let called = false if ((typeof x === 'object' && x !== null ) || typeof x === 'function' ) { let then = x.then try { if (typeof then === 'function' ) { then.call ( x, (y ) => { if (called) return called = true resolvePromise (promise2, y, resolve, reject) }, (r ) => { if (called) return called = true reject (r) } ) } else { resolve (x) } } catch (e) { if (called) return called = true reject (e) } } else { resolve (x) } }