浅谈用原生 JS 模仿个Promise 的实现

在尝试写一个 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。

所以冲突了,我决定再想想,如果想不出来就只能去参考源码了。