js 手写promise

css 复制代码
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
    #status = PENDING;
    #result = undefined;
    #handler = undefined;

    constructor(executor) {
        // 不能写在外面,因为this指向会出问题
        const resolve = (data) => {
            this.#changeState(FULFILLED, data);
        }

        const reject = (err) => {
            this.#changeState(REJECTED, err);
        }
    
        try {
            executor(resolve, reject);
        } catch(err) {
            reject(err); 
        }
    }

    #changeState (status, result) {
        if (this.#status !== PENDING) {
            return;
        }
        this.#status = status;
        this.#result = result;
        this.#run();
    }

    #run () {
        console.log(this, this.#handler);
        if (this.status === PENDING) {
            return;
        }
        const { onFulfilled, onRejected, resolve, reject } = this.#handler;
        // 回调不是函数,那么将当前的promise状态透传
        // 回调是函数,将函数执行返回值作为新的值传递,状态变为成功,执行过程报错,那么状态就为失败
        if(this.#status === FULFILLED) {
            if (typeof onFulfilled === 'function') {
                try {
                    const res = onFulfilled(this.#result);
                    resolve(res);
                } catch (err) {
                    reject(err);
                }
            } else {
                resolve(this.#result);
            }
        } else {
            if (typeof onRejected === 'function') {
                try {
                    const res = onRejected(this.#result);
                    resolve(res);
                } catch (err) {
                    reject(err);
                }
            } else {
                reject(this.#result);
            }
        }
    }

    then(onFulfilled, onRejected) {
        return  new MyPromise((resolve, reject) => {
            this.#handler = { onFulfilled, onRejected, resolve, reject };
            this.#run();
        });
    }
}

const p = new Promise((resolve, reject) => {
    // setTimeout(() => {
        reject(222);
    // }, 0);
    // resolve(111);
    // throw 123;
    // setTimeout(() => {
    //     throw 123;  // 异步错误捕获不到,Promise也是一样
    // }, 0);
});

p.then((res) => {
    console.log('成功1', res);
}, (err) => {
    console.log('失败1', err);
    return 333;
}).then(1, (err) => {
    console.log('失败2', err);
}).then((res) => {
    console.log('成功3', res);
}, (err) => {
    console.log('失败3', err);
}).then((res) => {
    console.log('成功4', res);
}, (err) => {
    console.log('失败4', err);
});

const p1 = new MyPromise((resolve, reject) => {
    // setTimeout(() => {
        reject(222);
    // }, 0);
    // resolve(111);
    // throw 123;
    // setTimeout(() => {
    //     throw 123;  // 异步错误捕获不到,Promise也是一样
    // }, 0);
});

p1.then((res) => {
    console.log('成功1', res);
}, (err) => {
    console.log('失败1', err);
    return 333;
}).then(1, (err) => {
    console.log('失败2', err);
}).then((res) => {
    console.log('成功3', res);
}, (err) => {
    console.log('失败3', err);
}).then((res) => {
    console.log('成功4', res);
}, (err) => {
    console.log('失败4', err);
});

其他静态方法

css 复制代码
	static resolve(value) {
        return new MyPromise((resolve) => resolve(value));
    }

    static reject(reason) {
        return new MyPromise((resolve, reject) => reject(reason));
    }

    static all(promises) {
        // 问题关键: 什么时候要执行resolve, 什么时候要执行reject
        return new MyPromise((resolve, reject) => {
            const values = [];
            promises.forEach((promise) => {
                promise.then(
                    (res) => {
                        values.push(res);
                        if (values.length === promises.length) {
                            resolve(values);
                        }
                    },
                    (err) => {
                        reject(err);
                    },
                );
            });
        });
    }

    static allSettled(promises) {
        return new MyPromise((resolve) => {
            const results = [];
            promises.forEach((promise) => {
                promise.then(
                    (res) => {
                        results.push({ status: PROMISE_STATUS_FULFILLED, value: res });
                        if (results.length === promises.length) {
                            resolve(results);
                        }
                    },
                    (err) => {
                        results.push({ status: PROMISE_STATUS_REJECTED, value: err });
                        if (results.length === promises.length) {
                            resolve(results);
                        }
                    },
                );
            });
        });
    }

    static race(promises) {
        return new MyPromise((resolve, reject) => {
            promises.forEach((promise) => {
                promise.then(resolve, reject);
            });
        });
    }

    static any(promises) {
        // resolve必须等到有一个成功的结果
        // reject所有的都失败才执行reject
        const reasons = [];
        return new MyPromise((resolve, reject) => {
            promises.forEach((promise) => {
                promise.then(resolve, (err) => {
                    reasons.push(err);
                    if (reasons.length === promises.length) {
                        reject(new AggregateError(reasons));
                    }
                });
            });
        });
    }
相关推荐
qq_1249870753几秒前
基于node.js+vue的医院陪诊系统的设计与实现(源码+论文+调试+安装+售后)
前端·vue.js·node.js·毕业设计
markyankee101几秒前
JavaScript中的this关键字:全面解析与实战指南
前端·javascript
去伪存真2 分钟前
如何集中管理多个项目的Jenkins Job 流程?
前端·jenkins
邹荣乐2 分钟前
uni-app多端应用开发:常见跨端兼容问题及处理策略
前端·微信小程序·uni-app
前端达人2 分钟前
React Router 是怎么实现灵活导航的?
前端·javascript·react.js·前端框架·ecmascript
青春:一叶知秋4 分钟前
【Qt开发】Qt音频
开发语言·qt
摘取一颗天上星️11 分钟前
Electron架构深度解析:用Web技术构建桌面应用的桥梁
前端·架构·electron
热心市民☆34 分钟前
C#中实现排序的方法并绑定到datagridview控件中
开发语言·c#
狮子座的男孩36 分钟前
解决:给整个 Vue 项目添加鼠标点击、鼠标移动、鼠标滚轮(DOM)事件,以达到后台延迟退出
javascript·vue.js·经验分享·dom树·鼠标移动事件·鼠标点击事件·鼠标滚轮事件
小赵学鸿蒙1 小时前
用Uniapp开发鸿蒙项目 五
前端