手写promise核心


// promise的核心部分用到观察者模式(收集依赖 -> 触发通知 -> 取出依赖执行 的方式)
// 在下方有频繁提及

class MyPromise {

    //先设置三种状态
    static PENDING = "等待中";
    static FULFILED = "接受";
    static REJECTED = "拒绝";

    //构造函数接收一个函数
    constructor(fn) {
        //为实例设置状态和结果
        this.status = MyPromise.PENDING;
        this.result = null;

        //保存then中的函数 一个promise可能有多个then let p = new Promise() p.then p.then()
        //promise是为了解决回调地域出现的,所以这也是promise的核心部分,利用回调实现异步的链式调用。
        this.resolvedCallbacks = [];
        this.rejectedCallbacks = [];

        //因为this.resolve this.reject 是实例化后才调用的,属于默认调用,要绑定实例this,避免resolve方法中的this出错
        fn(this.resolve.bind(this), this.reject.bind(this));
    };
    resolve(val) {
        //promise.then要设置成异步 避免阻塞第三步和第四步代码
        //使用settimeout将更改为异步 (当然也可以MutationObserver模拟微任务)
        setTimeout(() => {
            if (this.status !== MyPromise.PENDING) return;   // 对应规范中的"状态只能由pending到fulfilled或rejected" 也就是说不能resolve了又reject

            //判断状态是否是等待中,避免fullfiled又rejected
            if (this.status === MyPromise.PENDING) {

                this.status = MyPromise.FULFILED;
                this.result = val;

                //检是否有then放入的resolved函数
                this.resolvedCallbacks.forEach((fn) => {
                    fn(this.result);
                })

            }
        })
    };
    reject(val) {
        //同理
        setTimeout(() => {
            if (this.status !== MyPromise.PENDING) return;  // 对应规范中的"状态只能由pending到fulfilled或rejected" 也就是说不能resolve了又reject

            //判断状态是否是等待中,避免fullfiled又rejected
            if (this.status === MyPromise.PENDING) {
                this.status = MyPromise.REJECTED;
                this.result = val;


                this.rejectedCallbacks.forEach((fn) => {
                    fn(this.result);
                })

            }
        })
    };
    //then类方法接收两个参数
    then(onFULFILLED, onREJECTED) {

        //链式返回promise 由于是箭头函数 所以里面this不会出错
        return new MyPromise((resolve, reject) => {

            //这里是定义一个函数用于对promise和普通值返回 区分
            const fulfilledFn = value => {
                try {
                    //执行第一个(当前的)Promise的成功回调,并获取返回值
                    let x = onFULFILLED(value)
                    //分类讨论返回值,如果是Promise,那么等待Promise状态变更,否则直接resolve
                    //这里resolve之后,就能被下一个.then()的回调获取到返回值,从而实现链式调用
                    x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
                } catch (error) {
                    reject(error)
                }
            }

            //同理
            const rejectedFn = error => {

                try {
                    let x = onREJECTED(error)
                    x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
                } catch (error) {
                    reject(error)
                }
            }

            //这里的代码先于resolve函数,那么status是pendding
            //所以要将这个函数保存起来,让resolve回调完后调用
            //这里和resolvedCallbacks对应,是promise核心精华
            if (this.status === MyPromise.PENDING) {
                // //发布订阅
                this.resolvedCallbacks.push(fulfilledFn);
                this.rejectedCallbacks.push(rejectedFn);
            }

            //在then之前 promise状态已经改变 兼容以后promise.resolve().then()
            if (this.status === MyPromise.FULFILED) {
                fulfilledFn(this.result)
            }

            //同理
            if (this.status === MyPromise.REJECTED) {
                rejectedFn(this.reject)
            }

        })

    }
}
//代码执行步骤自测 严格按照步骤执行顺序来
console.log("第一步");
var mp = new MyPromise((resolve) => {
    console.log("第二步");
    setTimeout(function () {
        resolve("吃饭")
        console.log("第四步")
    }, 1500)
})
//then是异步方法,应该最后输出
mp.then(res => {
    console.log("最后一步:", res)

    //为新promise 提供值
    // return res;

    return new MyPromise((resolve) => {
        resolve(res)
    })
}).then(res => {
    console.log(res)
})
console.log("第三步")

//代码自测
console.log("第一步");
var mp = new MyPromise((resolve) => {
    console.log("第二步");
    setTimeout(function () {
        resolve("吃饭")
        console.log("第四步")
    }, 1500)
})
//then是异步方法,应该最后输出
mp.then(res => {
    console.log("最后一步:", res)

    //为新promise 提供值
    // return res;

    return new MyPromise((resolve) => {
        resolve(res)
    })
}).then(res => {
    console.log(res)
})
console.log("第三步")

文章作者: iamfugui
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 iamfugui !
评论