Promise详解 + 手写

72 阅读1分钟

Promise

class MyPromise {
    constructor(executor) {
        this.value = undefined;
        this.state = 'pending'; // 状态
        this.error = undefined;
        this.failCb = []; // 失败回调数组
        this.successCb = []; // 成功回调数组
        try {
            executor(this.resolve, this.reject);
        } catch(e) {
            this.reject(e);
        }
    }

    resolve = (val) => {
        if (this.state !== 'pending') return;
        this.state = 'fulfilled';
        this.value = val;
        while (this.successCb.length > 0) this.successCb.shift()(val);
    }

    reject = (err) => {
        if (this.state !== 'pending') return;
        this.error = err;
        this.state = 'rejected';
        while(this.failCb.length > 0) this.failCb.shift()(err);
    }

    then(sCb, fCb) {
        // 处理返回相同promise问题以及返回值类型
        const resolvePromise = (res, p, resolve, reject, state) => {
            if (res === p) throw 'same promise';
            if (res instanceof MP) res.then((v) => resolve(v), e => reject(e));
            else state === 'fulfilled' ? resolve(res) : reject(res);
        }
        const p = new MP((resolve, reject) => {
            // setTimerout是为了拿到p实例
            setTimeout(() => {
                if (this.state === 'fulfilled') {
                    const res = sCb(this.value);
                    resolvePromise(res, p, resolve, reject, 'fulfilled');
                }
                if (this.state === 'rejected') {
                    const res = fCb(this.error);
                    resolvePromise(res, p, resolve, reject, 'rejected');
                }
                if (this.state === 'pending') {
                    this.successCb.push(() => {
                        const res = sCb(this.value);
                    resolvePromise(res, p, resolve, reject, 'fulfilled');
                    });
                    this.failCb.push(() => {
                        const res = fCb(this.error);
                    resolvePromise(res, p, resolve, reject, 'rejected');
                    })
                }
            });
        });
        return p;
    }

    finally(cb) {
        return this.then((v) => {
            MP.resolve(cb()).then(() => v);
        }, (e) => {
            MP.resolve(cb()).then(() => { throw e });
        })
    }

    static resolve(p) {
        if (p instanceof MP) return p;
        return new MP((resolve) => resolve(p));
    }

    static all(arr) {
        const res = [];
        let count = 0;
        return new Promise((resolve, reject) => {
            arr.forEach((e) => {
                MP.resolve(e).then((v, i) => {
                    res[i] = v;
                    count++;
                    if (count === arr.length) resolve(res);
                }, (e) => {
                    reject(e);
                });
            })
        })
    }
    
    static allSettled(arr) {
        return new MP((resolve) => {
            const res = [];
            let count = 0;
            arr.forEach((e, i) => {
                MP.resolve(e).then((v) => {
                    res[i] = {
                        state: 'fulfilled',
                        value: v
                    };
                    count++;
                    if (count === arr.length) resolve(res);
                }, (err) => {
                    res[i] = {
                        state: 'rejected',
                        error: err
                    };
                    count++;
                    if (count === arr.length) resolve(res);
                });
            });
        });
    }
}