手写promise

本文侧重侧重讲解Promise的原理,如果对Promise使用不太熟的小伙伴可参考阮一峰老师的文章ECMAScript 6 入门
Promise有三种状态,分别是pending、fulfilled和reject,一旦改变便不会再更改。
所以第一步,我们把这个功能先实现。

export default class MyPromise {
    constructor(handle) {
        this['[[PromiseState]]'] = "pending" //Promise的状态
        this['[[PromiseResult]]'] = undefined; //Promise的值
        handle(this._resolve,this._reject)
    }
    _resolve = (val) => {
        //1.修改Promise的状态 2.修改Promise的值
        if (this['[[PromiseState]]'] === "pending") {
            this['[[PromiseState]]'] = "fulfilled"
            this['[[PromiseResult]]'] = val;
        }
    }
    _reject = (err) => {
        if (this['[[PromiseState]]'] === "pending") {
            this['[[PromiseState]]'] = "rejected";
            this['[[PromiseResult]]'] = err;
        }
    }
}

第二步 实现then方法,then方法可以接受两个回调函数作为参数。这个两个回调函数接受Promise的值作为参数。

export default class MyPromise {
    constructor(handle) {
        this['[[PromiseState]]'] = "pending" //promise的状态
        this['[[PromiseResult]]'] = undefined; //promise的值
        this.resolveFn = undefined;
        this.rejectFn = undefined;
        handle(this._resolve,this._reject)
    }
    _resolve = (val) => {
        //1.修改promise的状态 2.修改promise的值
        if (this['[[PromiseState]]'] === "pending") {
            this['[[PromiseState]]'] = "fulfilled"
            this['[[PromiseResult]]'] = val;
            setTimeout(()=>{
                this.resolveFn(val)
            })
        }
    }
    _reject = (err) => {
        if (this['[[PromiseState]]'] === "pending") {
            this['[[PromiseState]]'] = "rejected";
            this['[[PromiseResult]]'] = err;
            setTimeout(()=>{
                this.rejectFn(err)
            })
           
        }
    }
    then(onResolved,onRejected){
        this.resolveFn = onResolved;
        this.rejectFn = onRejected;
    }
}

写到此处then有4个问题还没解决 。
1.多个then的问题(不是链式调用)
即如下面这样多次调用then。

const p1 = new Promise((res)=>{
        setTimeout(()=>{
            res(1)
        })
    })
    p1.then((value)=>{
        console.log(value + 1) // 2
    })
    p1.then((value)=>{
        console.log(value + 2) // 3
    })

2、then的同步执行顺序问题(微任务、宏任务)。
3、then的链式调用。

第三步解决多个then的调用问题。将then接受的回调函数用数组收集起来,解决多个then的调用问题。

export default class MyPromise {
    constructor(handle) {
        this['[[PromiseState]]'] = "pending" //promise的状态
        this['[[PromiseResult]]'] = undefined; //promise的值
        this.onResolvedCallback = [] // Promise resolve时的回调函数集
        this.onRejectedCallback = [] // Promise reject时的回调函数集
        // this.resolveFn = undefined;
        // this.rejectFn = undefined;
        handle(this._resolve,this._reject)
    }
    _resolve = (val) => {
        //1.修改promise的状态 2.修改promise的值
        if (this['[[PromiseState]]'] === "pending") {
            this['[[PromiseState]]'] = "fulfilled"
            this['[[PromiseResult]]'] = val;
            setTimeout(()=>{
                let cb;
                while(cb = this.onResolvedCallback.shift()) {
                    typeof cb ==='function' && cb(val);
                }
            })
        }
    }
    _reject = (err) => {
        if (this['[[PromiseState]]'] === "pending") {
            this['[[PromiseState]]'] = "rejected";
            this['[[PromiseResult]]'] = err;
            setTimeout(()=>{
                let cb;
                while(cb = this.onRejectedCallback.shift()) {
                typeof cb ==='function' && cb(err);
                }
            })
           
        }
    }
    then(onResolved,onRejected){
        this.onResolvedCallback.push(onResolved);
        this.onRejectedCallback.push(onRejected);
    }
}

第四步、then的同步执行顺序问题。then里面的回调函数属于微任务,当前所有同步代码执行完毕然后执行then里面的回调函数,再执行定时器这些宏任务。

 const my = new MyPromise((res)=>{
        console.log('Promise')
        setTimeout(()=>{
            console.log(1)
        })
        res(2);
    });
    my.then((value)=>{
        console.log(value)
    });
    /*打印的顺序为promise、1、2,这个顺序是不对的。
    上述代码中,正确的执行顺序应该是,MyPromise新建后立即执行,首先输出Promise,然后输出2,最后输出1。

为了让then收集的回调函数执行的时候有微任务的效果,可以用MutationObserver模拟一下,MutationObserver的具体用法可以参照MDN

export default class MyPromise {
    constructor(handle) {
        this['[[PromiseState]]'] = "pending" //promise的状态
        this['[[PromiseResult]]'] = undefined; //promise的值
        this.onResolvedCallback = [] // Promise resolve时的回调函数集
        this.onRejectedCallback = [] // Promise reject时的回调函数集
        // this.resolveFn = undefined;
        // this.rejectFn = undefined;
        handle(this._resolve,this._reject)
    }
    _resolve = (val) => {
        //1.修改promise的状态 2.修改promise的值
        if (this['[[PromiseState]]'] === "pending") {
            this['[[PromiseState]]'] = "fulfilled"
            this['[[PromiseResult]]'] = val;
            const executor = () => {
                 let cb;
                while(cb = this.onResolvedCallback.shift()) {
                    typeof cb ==='function' && cb(val);
                }
            }
            const obj = new MutationObserver(executor);
            obj.observe(document.body,{
                attributes:true
            });
            document.body.setAttribute("Promise","MyPromise")
            // setTimeout(()=>{
            //     let cb;
            //     while(cb = this.onResolvedCallback.shift()) {
            //         typeof cb ==='function' && cb(val);
            //     }
            // })
        }
    }
    _reject = (err) => {
        if (this['[[PromiseState]]'] === "pending") {
            this['[[PromiseState]]'] = "rejected";
            this['[[PromiseResult]]'] = err;
            // setTimeout(()=>{
            //     let cb;
            //     while(cb = this.onRejectedCallback.shift()) {
            //     typeof cb ==='function' && cb(err);
            //     }
            // })
            const executor = () => {
                let cb;
               while(cb = this.onRejectedCallback.shift()) {
                   typeof cb ==='function' && cb(val);
               }
           }
           const obj = new MutationObserver(executor);
           obj.observe(document.body,{
               attributes:true
           });
           document.body.setAttribute("Promise","MyPromise")
           
        }
    }
    then(onResolved,onRejected){
        this.onResolvedCallback.push(onResolved);
        this.onRejectedCallback.push(onRejected);
    }
}

第五步、解决then的链式调用的问题。then调用后会返回一个新的Promise实例。

export default class MyPromise {
    constructor(handle) {
        this['[[PromiseState]]'] = "pending" //promise的状态
        this['[[PromiseResult]]'] = undefined; //promise的值
        this.onResolvedCallback = [] // Promise resolve时的回调函数集
        this.onRejectedCallback = [] // Promise reject时的回调函数集
        // this.resolveFn = undefined;
        // this.rejectFn = undefined;
        handle(this._resolve, this._reject)
    }
    _resolve = (val) => {
        //1.修改promise的状态 2.修改promise的值
        if (this['[[PromiseState]]'] === "pending") {
            this['[[PromiseState]]'] = "fulfilled";
            this['[[PromiseResult]]'] = val;
            const executor = () => {
                let cb;
                while (cb = this.onResolvedCallback.shift()) {
                    cb && cb(val);
                }
            }
            const obj = new MutationObserver(executor);
            obj.observe(document.body, {
                attributes: true
            });
            document.body.setAttribute("Promise", "MyPromise")
            // setTimeout(()=>{
            //     let cb;
            //     while(cb = this.onResolvedCallback.shift()) {
            //         typeof cb ==='function' && cb(val);
            //     }
            // })
        }
    }
    _reject = (err) => {
        if (this['[[PromiseState]]'] === "pending") {
            this['[[PromiseState]]'] = "rejected";
            this['[[PromiseResult]]'] = err;
            // setTimeout(()=>{
            //     let cb;
            //     while(cb = this.onRejectedCallback.shift()) {
            //     typeof cb ==='function' && cb(err);
            //     }
            // })
            const executor = () => {
                let cb;
                while (cb = this.onRejectedCallback.shift()) {
                    cb && cb(val);
                }
            }
            const obj = new MutationObserver(executor);
            obj.observe(document.body, {
                attributes: true
            });
            document.body.setAttribute("Promise", "MyPromise")

        }
    }
    then(onResolved, onRejected) {
        return new MyPromise((resolve,reject) => {
            const resloveFn = (val) => {
                const res = typeof onResolved === 'function' && onResolved(val);
                //如果then里面的回调函数返回的是一个Promise实例
                if (res instanceof MyPromise) {
                    res.then((result) => {
                        resolve(result)
                    })
                } else {
                    console.log(res,'执行的结果')
                    resolve(res)
                }
            }
            this.onResolvedCallback.push(resloveFn);
            const rejectFn = (err) => {
                typeof onRejected === 'function' && onRejected(err);
                reject(err);
            }
            this.onRejectedCallback.push(rejectFn);
        })

    }
}

第六步、Promise的一些其他静态方法

export default class MyPromise {
    constructor(handle) {
        this['[[PromiseState]]'] = "pending";//promise的状态
        this['[[PromiseResult]]'] = undefined; //promise的值
        this.onResolvedCallback = [];// Promise resolve时的回调函数集
        this.onRejectedCallback = [];// Promise reject时的回调函数集
        // this.resolveFn = undefined;
        // this.rejectFn = undefined;
        handle(this._resolve, this._reject);
    }
    _resolve = (val) => {
        //1.修改promise的状态 2.修改promise的值
        if (this['[[PromiseState]]'] === "pending") {
            this['[[PromiseState]]'] = "fulfilled";
            this['[[PromiseResult]]'] = val;
            const executor = () => {
                let cb;
                while (cb = this.onResolvedCallback.shift()) {
                    cb && cb(val);
                }
            }
            const obj = new MutationObserver(executor);
            obj.observe(document.body, {
                attributes: true
            });
            document.body.setAttribute("Promise", "MyPromise");
            // setTimeout(()=>{
            //     let cb;
            //     while(cb = this.onResolvedCallback.shift()) {
            //         typeof cb ==='function' && cb(val);
            //     }
            // })
        }
    }
    _reject = (err) => {
        if (this['[[PromiseState]]'] === "pending") {
            this['[[PromiseState]]'] = "rejected";
            this['[[PromiseResult]]'] = err;
            // setTimeout(()=>{
            //     let cb;
            //     while(cb = this.onRejectedCallback.shift()) {
            //     typeof cb ==='function' && cb(err);
            //     }
            // })
            const executor = () => {
                let cb;
                while (cb = this.onRejectedCallback.shift()) {
                    cb && cb(err);
                }
            }
            const obj = new MutationObserver(executor);
            obj.observe(document.body, {
                attributes: true
            });
            document.body.setAttribute("Promise", "MyPromise");

        }
    }
    then(onResolved, onRejected) {
        return new MyPromise((resolve, reject) => {
            const resloveFn = (val) => {
                const res = typeof onResolved === 'function' && onResolved(val);
                //如果then里面的回调函数返回的是一个Promise实例
                if (res instanceof MyPromise) {
                    res.then((result) => {
                        resolve(result);
                    })
                } else {
                    resolve(res);
                }
            }
            this.onResolvedCallback.push(resloveFn);
            const rejectFn = (err) => {
                typeof onRejected === 'function' && onRejected(err);
                reject(err);
            }
            this.onRejectedCallback.push(rejectFn);
        })

    }
    static resolve(value) {
        return new MyPromise(resolve => {
            resolve(value);
        })
    }
    static reject(err) {
        return new MyPromise((resolve, reject) => {
            reject(err);
        })
    }
    static race(arr) {
        return new MyPromise((resolve, reject) => {
            arr.forEach((promise) => {
                promise.then((value) => {
                    resolve(value);
                }, (error) => {
                    reject(error);
                })
            })
        })
    }
    static all(promises) {
        return new MyPromise((resolve) => {
            const result = [];
            let index = 0;
            let len = promises.length;
            if (len === 0) {
                resolve(result);
                return;
            }
            for (let i = 0; i < len; i++) {
                promises[i].then((res) => {
                    result[i] = res;
                    index++;
                    if (index === len) {
                        resolve(result);
                    }
                })
            }
        })

    }
    static allSettled(promises) {
        return new MyPromise((resolve, reject) => {
            const result = [];
            let index = 0;
            let len = promises.length;
            if (len === 0) {
                resolve(result);
            }
            for(let i = 0; i < len; i++){
                const obj = {};
                promises[i].then((val)=>{
                    obj.status = "fulfilled";
                    obj.value = val;
                    result[i] = obj;
                    index++;
                    if (index === len) {
                        resolve(result);
                    }
                },(err)=>{
                    obj.status = "rejected";
                    obj.reason = err;
                    result[i] = obj;
                    index++;
                    if (index === len) {
                        resolve(result);
                    }
                })
                
            }
        })
    }

}

本文虽然有一些细节的地方没考虑周全,达不到Promise/A+的标准,但基本雏形都在适合第一次手写Promise的小伙伴入个门。

上一篇:WPF 命令


下一篇:第十二届蓝桥杯CB省赛复盘