在尝试写一个 Promise 的时候,没有看任何的开源代码,我觉得这样遇到的问题才足够真实。
2018-05-15 11:10
目前只能做到这样:
const Promise = function( callback ) { if(typeof callback !== 'function') { throw new Error(`Promise resolver ${ callback } is not a function`) } const PROMISE_STATUS = '[[PromiseStatus]]'; const PROMISE_VALUE = '[[PromiseValue]]'; this[PROMISE_STATUS] = 'pending'; this[PROMISE_VALUE] = undefined; let resolveFn, rejectFn, isThen, isCatch, finallyFn; Object.defineProperty(this, PROMISE_STATUS, { set: ( newVal ) => { const value = this[ PROMISE_VALUE ]; if( newVal === 'fulfilled' && isThen ) { resolveFn && resolveFn( value ) } if( newVal === 'rejected' && isCatch ) { rejectFn && rejectFn( value ) } finallyFn && finallyFn( value ) } }); const resolve = ( response ) => { if( isCatch ) return; setTimeout(() => { isThen = true; this[ PROMISE_VALUE ] = response; this[ PROMISE_STATUS ] = 'fulfilled'; }, 0) }; const reject = ( error ) => { if( isThen ) return; setTimeout(() => { isCatch = true; this[ PROMISE_VALUE ] = error; this[ PROMISE_STATUS ] = 'rejected'; }, 0) // const e = new Error( error ); // e.stack = ''; // e.name = '(in Promise)'; // throw e }; Promise.prototype.then = function ( callback ) { if( isCatch ) return; resolveFn = callback; return this; }; Promise.prototype.catch = function ( callback ) { if( isThen ) return; rejectFn = callback; return this; }; Promise.prototype.finally = function( callback ) { finallyFn = callback; return this; }; callback( resolve, reject ); };
这里是借鉴了 Vue 双向数据绑定的实现方法,在状态改变的时候执行对应的 then / catch / finally 方法。
但是这里没办法链式调用,遇到了一个矛盾的地方。下面的示例仅仅按 .then().catch().finally() 这样调用的顺序讲
1、then 方法如果不返回实例本身,那么 catch 和 finally 方法就没办法链式调用,因为 this 的指向不是原实例了。
2、then 方法如果返回实例本身,那么 .then().then() 第二次 then 方法的 this 那依然只是那一个实例,这里应该是,如果上一次 then 方法的返回值是一个 Promise 则是这个 Promise,如果不是 Promise,则是一个新的 Promise。
所以冲突了,我决定再想想,如果想不出来就只能去参考源码了。