Javascript Promise的简单模拟实现

84 阅读5分钟

「这是我参与11月更文挑战的第23天,活动详情查看:2021最后一次更文挑战

Javascript Promise的简单模拟实现

promise可以说是前端工程师必备的技术点了。之前不管是面试还是开发中经常有用到promise,有些特性也是一边学一边忘。通过对promise的简单模拟实现了解其原理,可能会对promise更加深刻。可能不是特别完美,主要还是做一个学习交流。

一、promise的特点和功能

在实现之前,我们先来梳理一下promise的特点和功能,看看具体要实现哪些功能,一步一步拆解开来实现。

  1. 属性:
  • 状态(state)
  • 值(value)
  • 回调函数列表
  1. 方法:

实例方法:

  • executor 执行器调用
  • resolve,reject

原型方法:

  • then
  • catch
    静态方法:
  • resolve,reject
  • all,race

二、实现步骤

1. 构造器

首先先来实现构造器,在构造器中主要是定义了实例属性和实例方法,也就是上面提到的:

  • 状态(state)
  • 值(value)
  • 回调函数列表
  • executor 执行器调用
  • resolve,reject

回顾一下这些的特点

  1. promise对象有三种状态pendingresolvedrejected
  2. 状态只有两种变化方向pending=>resolvedpending=>rejected,而且状态一旦更改就不能再改变
  3. 值的变化也是随着状态的改变而发生改变的,所以值也只能改变一次
  4. 执行器是在构造函数中同步调用的。
  5. resolve和reject分别会作为参数传入执行器中。
  6. 在执行器中调用resolvereject方法可以将promise对象的状态分别改变为resolvedrejected
    根据上面的特点可以简单实现一个构造器
class _Promise {
    //构造方法
    constructor(executor) {
        const that = this
        that.state = PENDING;
        that.value = undefined;
        that.resolvedCallbacks = []
        that.rejectedCallbacks = []
        //resolve 函数
        function resolve(data) {
            if (val instanceof _Promise) {
                return val.then(that.resolve, that.reject)
            }
            setTimeout(() => {
                if (that.state === PENDING) {
                    that.state = RESOLVED
                    that.value = val
                    that.resolvedCallbacks.map(callback => callback(val))
                }
            }, 0)
        }
        //reject 函数
        function reject(data) {
            setTimeout(() => {
                if (that.state === PENDING) {
                    that.state = REJECTED
                    that.value = val
                    that.rejectedCallbacks.map(callback => callback(val))
                }
            }, 0)
        }
        try {
            //同步调用『执行器函数』
            executor(resolve, reject);
        } catch (e) {
            //修改 promise 对象状态为『失败』
            reject(e);
        }
    }
}

原型方法 then,catch

来梳理一下then和catch的特点

  1. promsie的一个特点是链式调用,为了实现这个then和catch方法返回的都是一个新的promise对象
  2. then方法的功能主要是注册或执行回调函数
  • 若promise实例的状态是pending,则将回调函数注册到promise实例的回调函数列表中
  • 若promise实例的状态发生了改变,为resolvedrejected,则直接执行对应的回调函数。
  1. then的两个参数可以传也可以不传,如果传了必须是函数类型,所以需要做一个兜底提高兼容性。
  2. catch方法其实就是特殊的then方法,catch(onRejected) = then(undefined, onRejected);
    then(onfullfilled, onrejected) {
        let that = this
        let p2

        onfullfilled = typeof onfullfilled === `function` ? onfullfilled : v => v
        onrejected = typeof onrejected === `function` ? onrejected : v => { throw v }

        if (that.state === PENDING) {
            return (p2 = new _Promise((resolve, reject) => {
                that.resolvedCallbacks.push(() => {
                    onfullfilled(that.value)
                    resolve()
                })
                that.rejectedCallbacks.push(() => {
                    onrejected(that.value)
                    reject()
                })
            }))
        }
        if (that.state === RESOLVED) {
            return (p2 = new _Promise((resolve, reject) => {
                onfullfilled(that.value)
                resolve()
            }))
        }
        if (that.state === REJECTED) {
            return (p2 = new _Promise((resolve, reject) => {
                onrejected(that.value)
                reject()
            }))
        }
    }
    catch(onRejected) {
        return this.then(undefined, onRejected);
    }

3. 静态方法 resolve,reject,all,race

这里的resolve和reject和刚刚提到的是不同的函数。 来梳理一下这几个静态方法的特点

  1. resolve和reject方法直接返回一个状态已变化值为函数参数的promise实例

  2. all和race方法返回的也是一个新的promise实例,但是这个promise实例的状态的确定方式不同

  3. all 方法在传入的所有promise实例的状态都为resolved时返回的新的promise实例的状态才是resolved,否则都是rejected
    race 方法顾名思义,只要传入的promise实例中有一个状态发生改变,就进行返回,并且返回的新的promise实例的值和状态都和该promise实例保持一致。

    //添加 resolve 方法
    static resolve(value) {
        //返回promise对象
        return new Promise((resolve, reject) => {
            if (value instanceof Promise) {
                value.then(v => {
                    resolve(v);
                }, r => {
                    reject(r);
                })
            } else {
                //状态设置为成功
                resolve(value);
            }
        });
    }

    //添加 reject 方法
    static reject(reason) {
        return new Promise((resolve, reject) => {
            reject(reason);
        });
    }

    //添加 all 方法
    static all(promises) {
        //返回结果为promise对象
        return new Promise((resolve, reject) => {
            //声明变量
            let count = 0;
            let arr = [];
            //遍历
            for (let i = 0; i < promises.length; i++) {
                //
                promises[i].then(v => {
                    //得知对象的状态是成功
                    //每个promise对象 都成功
                    count++;
                    //将当前promise对象成功的结果 存入到数组中
                    arr[i] = v;
                    //判断
                    if (count === promises.length) {
                        //修改状态
                        resolve(arr);
                    }
                }, r => {
                    reject(r);
                });
            }
        });
    }

    //添加 race 方法
    static race(promises) {
        return new Promise((resolve, reject) => {
            for (let i = 0; i < promises.length; i++) {
                promises[i].then(v => {
                    //修改返回对象的状态为 『成功』
                    resolve(v);
                }, r => {
                    //修改返回对象的状态为 『失败』
                    reject(r);
                })
            }
        });
    }
}

三、完整的代码

const PENDING = `pending`
const RESOLVED = `resolved`
const REJECTED = `rejected`

class _Promise {
    //构造方法
    constructor(executor) {
        const that = this
        that.state = PENDING;
        that.value = undefined;
        that.resolvedCallbacks = []
        that.rejectedCallbacks = []
        //resolve 函数
        that.resolve = function (val) {
            if (val instanceof _Promise) {
                return val.then(that.resolve, that.reject)
            }
            setTimeout(() => {
                if (that.state === PENDING) {
                    that.state = RESOLVED
                    that.value = val
                    that.resolvedCallbacks.map(callback => callback(val))
                }
            }, 0)
        }
        //reject 函数
        that.reject = function (val) {
            setTimeout(() => {
                if (that.state === PENDING) {
                    that.state = REJECTED
                    that.value = val
                    that.rejectedCallbacks.map(callback => callback(val))
                }
            }, 0)
        }
        try {
            //同步调用『执行器函数』
            fn(that.resolve, that.reject)
        } catch (error) {
            //修改 promise 对象状态为『失败』
            that.reject(error)
        }
    }

    //then 方法封装
    then(onfullfilled, onrejected) {
        let that = this
        let p2

        onfullfilled = typeof onfullfilled === `function` ? onfullfilled : v => v
        onrejected = typeof onrejected === `function` ? onrejected : v => { throw v }

        if (that.state === PENDING) {
            return (p2 = new _Promise((resolve, reject) => {
                that.resolvedCallbacks.push(() => {
                    onfullfilled(that.value)
                    resolve()
                })
                that.rejectedCallbacks.push(() => {
                    onrejected(that.value)
                    reject()
                })
            }))
        }
        if (that.state === RESOLVED) {
            return (p2 = new _Promise((resolve, reject) => {
                onfullfilled(that.value)
                resolve()
            }))
        }
        if (that.state === REJECTED) {
            return (p2 = new _Promise((resolve, reject) => {
                onrejected(that.value)
                reject()
            }))
        }
    }

    //catch 方法
    catch(onRejected) {
        return this.then(undefined, onRejected);
    }

    //添加 resolve 方法
    static resolve(value) {
        //返回promise对象
        return new Promise((resolve, reject) => {
            if (value instanceof Promise) {
                value.then(v => {
                    resolve(v);
                }, r => {
                    reject(r);
                })
            } else {
                //状态设置为成功
                resolve(value);
            }
        });
    }

    //添加 reject 方法
    static reject(reason) {
        return new Promise((resolve, reject) => {
            reject(reason);
        });
    }

    //添加 all 方法
    static all(promises) {
        //返回结果为promise对象
        return new Promise((resolve, reject) => {
            //声明变量
            let count = 0;
            let arr = [];
            //遍历
            for (let i = 0; i < promises.length; i++) {
                //
                promises[i].then(v => {
                    //得知对象的状态是成功
                    //每个promise对象 都成功
                    count++;
                    //将当前promise对象成功的结果 存入到数组中
                    arr[i] = v;
                    //判断
                    if (count === promises.length) {
                        //修改状态
                        resolve(arr);
                    }
                }, r => {
                    reject(r);
                });
            }
        });
    }

    //添加 race 方法
    static race(promises) {
        return new Promise((resolve, reject) => {
            for (let i = 0; i < promises.length; i++) {
                promises[i].then(v => {
                    //修改返回对象的状态为 『成功』
                    resolve(v);
                }, r => {
                    //修改返回对象的状态为 『失败』
                    reject(r);
                })
            }
        });
    }
}

小白的简单实现,如果要符合promise的A+规范,可能还要做非常多优化,欢迎大佬们提出建议。