实现简单的Promise

什么是Promise

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise提供统一的API,各种异步操作都可以用同样的方法进行处理。

Promise出现之前都是通过回调函数来实现,回调函数本身没有问题,但是嵌套层级过深,很容易掉进回调地狱。

const fs = require('fs');
fs.readFile('1.txt', (err,data) => {
    fs.readFile('2.txt', (err,data) => {
        fs.readFile('3.txt', (err,data) => {
            //可能还有后续代码
        });
    });
});

如果每次读取文件后还要进行逻辑的判断或者异常的处理,那么整个回调函数就会非常复杂且难以维护。Promise的出现正是为了解决这个痛点,我们可以把上面的回调嵌套用Promise改写一下:

const readFile = function(fileName){
    return new Promise((resolve, reject)=>{
        fs.readFile(fileName, (err, data)=>{
            if(err){
                reject(err)
            } else {
                resolve(data)
            }
        })
    })
}

readFile('1.txt')
    .then(data => {
        return readFile('2.txt');
    }).then(data => {
        return readFile('3.txt');
    }).then(data => {
        //...
    });

Promise规范

promise最早是在commonjs社区提出来的,当时提出了很多规范。比较接受的是promise/A规范。但是promise/A规范比较简单,后来人们在这个基础上,提出了promise/A+规范,也就是实际上的业内推行的规范;es6也是采用的这种规范,但是es6在此规范上还加入了Promise.all、Promise.race、Promise.catch、Promise.resolve、Promise.reject等方法。

首先看出来,Promise是通过构造函数实例化一个对象,然后通过实例对象上的then方法,来处理异步返回的结果。同时,promise/A+规范规定了:

promise 是一个拥有 then 方法的对象或函数,其行为符合本规范;
一个 Promise 的当前状态必须为以下三种状态中的一种:等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected)。
// 定义一个表示promise的状态
    status_m = {
        PENDING: "PENDING",
        FULFILLED: "FULFILLED",
        REJECTED: "REJECTED",
    };
    // 设置默认的状态为PENDING
    #status = this.status_m.PENDING;
    // 存储promise成功的值
    #value;
    // 存储promise失败的值
    #reason;
    // 定义一个存储回调函数的函数池
    #callbacks = [];

不可变

promise/A+规范中规定,当Promise对象已经由等待态(Pending)改变为执行态(Fulfilled)或者拒绝态(Rejected)后,就不能再次更改状态,且终值也不可改变。

// 定义一个执行成功的方法
    #resolve(value) {
        // 判断当前promise的状态只要不是PENDING就直接返回不能修改
        if (this.#status !== this.status_m.PENDING) return;
        // 改变状态为成功
        this.#status = this.status_m.FULFILLED;
        // 将成功的值拿到
        this.#value = value;
        // 执行存储在函数池中的成功的resolve函数
        queueMicrotask(() => {
            this.#callbacks.forEach((c) => {
                c.resolve();
            });
        });
    }
    //定义promise失败的执行方法
    #reject(reason) {
        if (this.#status !== this.status_m.PENDING) return;
        this.#status = this.status_m.REJECTED;
        this.#reason = reason;
        queueMicrotask(() => {
            this.#callbacks.forEach((c) => {
                c.reject();
            });
        });
    }

支持异步

那么如何让我们的Promise来支持异步呢?我们可以参考发布订阅模式,在执行then方法的时候,如果当前还是PENDING状态,就把回调函数寄存到一个数组中,当状态发生改变时,去数组中取出回调函数;因此我们先在Promise中定义一下变量:

// 定义一个存储回调函数的函数池
    #callbacks = [];
// 当状态为PENDING时表示还没有进入修改需要将回调存放在函数池中
            if (this.#status === this.status_m.PENDING) {
                this.#callbacks.push({
                    resolve() {
                        try {
                            resolve(onFulfilled(that.#value));
                        } catch (e) {
                            reject(e);
                        }
                    },
                    reject() {
                        try {
                            reject(onRejected(that.#reason));
                        } catch (e) {
                            console.log(e);

                            reject(e);
                        }
                    },
                });
            }

then实现

当Promise的状态改变之后,不管成功还是失败,都会触发then回调函数。因此,then的实现也很简单,就是根据状态的不同,来调用不同处理终值的函数。

//   这里的then方法是需要暴露给外界使用,就不是私有的
    then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (cd) => cd;
        onRejected =
            typeof onRejected === "function"
                ? onRejected
                : (reason) => {
                    throw new Error(reason);
                };

        // 保存一下this
        const that = this;
        return new MyPromise((resolve, reject) => {
            // 当状态为PENDING时表示还没有进入修改需要将回调存放在函数池中
            if (this.#status === this.status_m.PENDING) {
                this.#callbacks.push({
                    resolve() {
                        try {
                            resolve(onFulfilled(that.#value));
                        } catch (e) {
                            reject(e);
                        }
                    },
                    reject() {
                        try {
                            reject(onRejected(that.#reason));
                        } catch (e) {
                            console.log(e);

                            reject(e);
                        }
                    },
                });
            } else if (this.#status === this.status_m.FULFILLED) {
                try {
                    queueMicrotask(() => {
                        resolve(onFulfilled(this.#value));
                    });
                } catch (e) {
                    reject(e);
                }
            } else if (this.#status === this.status_m.REJECTED) {
                try {
                    queueMicrotask(() => {
                        reject(onRejected(this.#reason));
                    });
                } catch (e) {
                    reject(e);
                }
            }
        });
    }

完整代码

/*
自定义一个MyPromise来实现promise一些功能

*/

class MyPromise {
    // 定义一个表示promise的状态
    status_m = {
        PENDING: "PENDING",
        FULFILLED: "FULFILLED",
        REJECTED: "REJECTED",
    };
    // 设置默认的状态为PENDING
    #status = this.status_m.PENDING;
    // 存储promise成功的值
    #value;
    // 存储promise失败的值
    #reason;
    // 定义一个存储回调函数的函数池
    #callbacks = [];
    // 定义一个执行器
    constructor(executor) {
        try {
            // 这里使用bind()绑定this是应为执行器是一个函数,这里的this指向是调用执行器的实例所以得绑定this
            executor(this.#resolve.bind(this), this.#reject.bind(this));
        } catch (e) {
            console.log(e);
            this.#reject(e);
        }
    }
    // 定义一个执行成功的方法
    #resolve(value) {
        // 判断当前promise的状态只要不是PENDING就直接返回不能修改
        if (this.#status !== this.status_m.PENDING) return;
        // 改变状态为成功
        this.#status = this.status_m.FULFILLED;
        // 将成功的值拿到
        this.#value = value;
        // 执行存储在函数池中的成功的resolve函数
        queueMicrotask(() => {
            this.#callbacks.forEach((c) => {
                c.resolve();
            });
        });
    }
    //定义promise失败的执行方法
    #reject(reason) {
        if (this.#status !== this.status_m.PENDING) return;
        this.#status = this.status_m.REJECTED;
        this.#reason = reason;
        queueMicrotask(() => {
            this.#callbacks.forEach((c) => {
                c.reject();
            });
        });
    }
    //   这里的then方法是需要暴露给外界使用,就不是私有的
    then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (cd) => cd;
        onRejected =
            typeof onRejected === "function"
                ? onRejected
                : (reason) => {
                    throw new Error(reason);
                };

        // 保存一下this
        const that = this;
        return new MyPromise((resolve, reject) => {
            // 当状态为PENDING时表示还没有进入修改需要将回调存放在函数池中
            if (this.#status === this.status_m.PENDING) {
                this.#callbacks.push({
                    resolve() {
                        try {
                            resolve(onFulfilled(that.#value));
                        } catch (e) {
                            reject(e);
                        }
                    },
                    reject() {
                        try {
                            reject(onRejected(that.#reason));
                        } catch (e) {
                            console.log(e);

                            reject(e);
                        }
                    },
                });
            } else if (this.#status === this.status_m.FULFILLED) {
                try {
                    queueMicrotask(() => {
                        resolve(onFulfilled(this.#value));
                    });
                } catch (e) {
                    reject(e);
                }
            } else if (this.#status === this.status_m.REJECTED) {
                try {
                    queueMicrotask(() => {
                        reject(onRejected(this.#reason));
                    });
                } catch (e) {
                    reject(e);
                }
            }
        });
    }
}

export default MyPromise;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值