请实现一个符合Promise/A+规范的Promise

36 阅读1分钟

"```javascript const PENDING = 'pending'; const FULFILLED = 'fulfilled'; const REJECTED = 'rejected';

class MyPromise { constructor(executor) { this.status = PENDING; this.value = undefined; this.reason = undefined; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = [];

    const resolve = (value) => {
        if (this.status === PENDING) {
            this.status = FULFILLED;
            this.value = value;
            this.onFulfilledCallbacks.forEach(callback => callback());
        }
    };

    const reject = (reason) => {
        if (this.status === PENDING) {
            this.status = REJECTED;
            this.reason = reason;
            this.onRejectedCallbacks.forEach(callback => callback());
        }
    };

    try {
        executor(resolve, reject);
    } catch (error) {
        reject(error);
    }
}

then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; };

    const promise2 = new MyPromise((resolve, reject) => {
        if (this.status === FULFILLED) {
            setTimeout(() => {
                try {
                    const x = onFulfilled(this.value);
                    resolvePromise(promise2, x, resolve, reject);
                } catch (error) {
                    reject(error);
                }
            }, 0);
        } else if (this.status === REJECTED) {
            setTimeout(() => {
                try {
                    const x = onRejected(this.reason);
                    resolvePromise(promise2, x, resolve, reject);
                } catch (error) {
                    reject(error);
                }
            }, 0);
        } else if (this.status === PENDING) {
            this.onFulfilledCallbacks.push(() => {
                setTimeout(() => {
                    try {
                        const x = onFulfilled(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        reject(error);
                    }
                }, 0);
            });
            this.onRejectedCallbacks.push(() => {
                setTimeout(() => {
                    try {
                        const x = onRejected(this.reason);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        reject(error);
                    }
                }, 0);
            });
        }
    });

    return promise2;
}

catch(onRejected) {
    return this.then(null, onRejected);
}

}

function resolvePromise(promise, x, resolve, reject) { if (promise === x) { return reject(new TypeError('Chaining cycle detected for promise')); }

let called = false;

if (x instanceof MyPromise) {
    x.then(
        value => {
            if (called) return;
            called = true;
            resolvePromise(promise, value, resolve, reject);
        },
        reason => {
            if (called) return;
            called = true;
            reject(reason);
        }
    );
} else {
    resolve(x);
}

}