【前端基础-javaScript】面试题:手撸一波Promise

91 阅读3分钟

1. 代码思路

1.1 整体思路

Promise的链式调用核心就是发布订阅者模式。 就是将then后面的方法作为回调函数注册到一个任务队列当中去,等到reslove或者reject方法执行完毕之后,将对应任务队列然后再执行任务队列中的函数。

因此当我们我们将reslovereject放到异步任务中,等到异步任务执行完毕之后,将结果保存到reslovereject,这时候Promise开始执行任务队列中的回到函数,达到链式调用的效果。

1.2 先写架构

Promise 传入一个execute方法,这个方法接受两个参数,resolve和reject

Promise 常量:三个状态 PENDING RESOLVED REJECTED

Promise 变量:状态state,执行结果value,以及resolve和reject执行结束后的回调方法队列

const PENDING = 'pending';
const RESOLVED = 'resolved';
const REJECTED = 'rejected';

function MyPromise(execute) {

    this.state = PENDING;
    this.value = null;
    this.resolvedcallBack = [];
    this.rejectedCallBack = [];

    function resolve(value) {

    }

    function reject(value) {

    }


    try {
        execute(resolve, reject);
    } catch (err) {
        reject(err)
    }
}

1.3 resolve(value)

因为使用的是构造函数实现,所以是self保留this对象,值得函数内部能够调用this的属性。

这一步考虑resolve(value)中的value值是Promise对象的情况,并延迟执行resove方法。

realove方法的执行放在setTimeout里面,保证reslove异步执行顺序。

function resolve(value) {
    //value是一个promise,则状态改变需要等待前一个状态改变,等上一函数执行完之后,再执行reslove
    if (value instanceof MyPromise) {
        return value.then(resolve, reject);
    }

    // resolve 异步执行
    setTimeout(function () {
        self.state = RESOLVED;
        self.value = value;
        self.resolvedcallBack.forEach((callBack) => {
            callBack(value);
        });
    }, 0)
}

1.3 then() 不添加链式调用

MyPromise.prototype.then = function (onResolved, onRejected) {
    // 如果没有参数或者不是一个function,赋予一个默认函数
    onResolved = typeof (onResolved) === 'function' ? onResolved : function (data) {
        return data;
    }
    onRejected = typeof (onRejected) === 'function' ? onRejected : function (err) {
        return err;
    }
    //如果异步执行
    if (this.state === PENDING) {
        this.resolvedcallBack.push(onResolved);
        this.rejectedCallBack.push(onRejected);
    }
    //如果同步执行
    if (this.state === RESOLVED) {
        this.resolvedcallBack.push(onResolved);
    }
    if (this.state === REJECTED) {
        this.rejectedCallBack.push(onRejected);
    }
}

1.4 then() 添加链式调用

链式调用是什么?客官请看,下面这个代码,能够输出 then,2 ,就是链式调用。其实很简单,我们只需要稍微包装一下下,就功德圆满了。

new MyPromise((resolve, reject) => {
    resolve('1');
}).then(data => {
    console.log('yes', data);
    return 2;
}).then(data=>{
    console.log('then',data)
})

就是then方法执行完默认返回一个promise对象,并且这个promise对象肯定得有resolve或者reject点什么东西?

肯定是reslove或者reject then(onResolved, onRejected)方法两个回调函数的返回值了。

  1. 所以第一步,then方法里面先return一个Promise对象,第一个需求完成了。

  2. 然后第二步,这下我们不直接将onResolved, onRejected两个方法放到队列了放什么呢?我们将这两个函数封装一下,封装成一个新函数rejected和rejected,这个新函数里面同样会执行会执行onResolved, onRejected两个方法,同样也还是会将执行后的返回值reslove或者reject 起来,第二件大事也完成了,功德圆满。

MyPromise.prototype.then = function (onResolved, onRejected) {
    onResolved = typeof (onResolved) === 'function' ? onResolved : function (data) {
        return data;
    }
    onRejected = typeof (onRejected) === 'function' ? onRejected : function (err) {
        return err;
    }
    const self = this;

    return new MyPromise((resolve, reject) => {

        // 对then中的函数进行进一步的封装,then方法的执行结果,使用resolve保存起来
        let resolved = function () {
            try {
                const result = onResolved(self.value);

                // 返回的是resolve(result)
                return resolve(result);
            } catch (err) {
                reject(err);
            }

        }

        let rejected = function () {
            try {
                const result = onRejected(self.value);

                // 返回的是resolve(result)
                return reject(result);
            } catch (err) {
                reject(err);
            }

        }

        //如果异步执行
        if (this.state === PENDING) {
            this.resolvedcallBack.push(resolved);
            this.rejectedCallBack.push(rejected);
        }
        //如果同步执行
        if (this.state === RESOLVED) {
            this.resolvedcallBack.push(resolved);
        }
        if (this.state === REJECTED) {
            this.rejectedCallBack.push(rejected);
        }
    })

}

2. 全部代码

const PENDING = "pending";
const RESOLVE = 'resolve';
const REJECT = 'reject';

function MyPromise(execute) {

    let self = this;

    this.state = PENDING;
    this.value = null;
    this.resoleCallBack = [];
    this.rejectCallBack = [];

    function resolve(value) {
        if (value instanceof MyPromise) return value.then(resolve, reject());

        setTimeout(function () {
            if (self.state === PENDING) {
                self.state = RESOLVE;
                self.value = value;
                self.resoleCallBack.forEach((callBack) => {
                    callBack(value);
                })
            }
        }, 0)

    }

    function reject(value) {
        if (value instanceof MyPromise) return value.then(resolve, reject());

        setTimeout(function () {
            if (self.state === PENDING) {
                self.state = REJECT;
                self.value = value;
                self.rejectCallBack.forEach((callBack) => {
                    callBack(value);
                })
            }
        }, 0)
    }

    try {
        execute(resolve, reject)
    } catch (e) {
        reject(e);
    }
}

MyPromise.prototype.then = function (onResolved, onRejected) {
    onResolved = typeof onResolved === 'function' ? onResolved : function (value) {
        return value;
    }

    onRejected = typeof onRejected === 'function' ? onRejected : function (err) {
        return err;
    }

    if (this.state === PENDING) {
        this.resoleCallBack.push(onResolved);
        this.rejectCallBack.push(onRejected);
    }

    if (this.state === RESOLVE) {
        onResolved(this.value);
    }
    if (this.state === REJECT) {
        onRejected(this.value);
    }
}

new MyPromise((resolve, reject) => {
    reject('err');
}).then(data => {
    console.log('yes',data);
},err=>{
    console.log("no",err)
})

[1] juejin.cn/post/684490…

[2] juejin.cn/post/694613…