手撕面试官之手写Promise(遭老罪喽)

121 阅读6分钟

今天去了一个高级CBD大楼,16层,进入了一个大公司,hr招来了一个其貌不扬的面试官,面试官戴着眼镜,上来轻蔑的看着我,问道:

你能手写promise吗?

心想:必须会!机会这不就来了,轻视我,我必须给你点颜色看看!

捋一下,一个promise需要的哪些信息, 我灵光一闪,首先想到:resolve,reject,then这3个核心 ok,以这三个模块,搭建基本架子。

class MyPromise{
    constructor(executor){

    }
    resolve(){

    }
    reject(){

    }
    then(){

    }
}


resolve,reject,肯定有对应的状态,联系到初始化数据,状态与返回值


class MyPromise{
    constructor(executor){
        //初始化数据
        this.initValue();
    }
    initValue(){
       //初始化为pending等待状态
       this.promiseState = 'pending';
       this.promiseResult = null;
    }

    resolve(value){
       //不是等待状态,说明已经成功或失败了,只有等待状态才会  resolve() || reject()
       if(this.promiseState != 'pending'){
          return;
       }
       //状态改为成功
       this.promiseState = 'fulfilled';
       this.promiseResult = value;

    }
    reject(reason){
        //不是等待状态,说明已经成功或失败了,只有等待状态才会  resolve() || reject()
        if(this.promiseState != 'pending'){
          return;
        }
        //状态改为失败
       this.promiseState = 'rejected';
       this.promiseResult = reason;
    }
    then(){

    }
}

当我写到这,面试官露出了不易察觉的嘲讽,我心想不好,肯定是哪出了问题! 看了一遍代码,回想到平时用的promise,确实发现了问题 没有给promise初始化try{}catch(){},没有执行executor函数 赶紧加上

class MyPromise{
    constructor(executor){
        //初始化数据
        this.initValue();
        //throw捕获
        try{
            //执行传进来的函数
            executor(this.resolve,this.reject);  
        }catch(e){
            //throw抛错误直接走reject
            this.reject(e);
        }
    }
    initValue(){
       //初始化为pending等待状态
       this.promiseState = 'pending';
       this.promiseResult = null;
    }

    resolve(value){
       //不是等待状态,说明已经成功或失败了,只有等待状态才会  resolve() || reject()
       if(this.promiseState != 'pending'){
          return;
       }
       //状态改为成功
       this.promiseState = 'fulfilled';
       this.promiseResult = value;

    }
    reject(reason){
        //不是等待状态,说明已经成功或失败了,只有等待状态才会  resolve() || reject()
        if(this.promiseState != 'pending'){
          return;
        }
        //状态改为失败
       this.promiseState = 'rejected';
       this.promiseResult = reason;
    }
    then(){

    }
}


赶紧测试一下:

let a = new MyPromise((resolve,reject)=>{
    resolve('成功!')
});

let b = new MyPromise((resolve,reject)=>{
    reject('失败!')
});

console.log(a);  //{"promiseState": "rejected", promiseResult: TypeError: Cannot read properties of undefined (reading 'promiseState')at resolve

此时面试官看着我的打印结果,推了眼镜,刚准备开口,我立马知道了问题处在哪里!没有给resolve与reject初始化this指向

class MyPromise{
    constructor(executor){
        //初始化数据
        this.initValue();
        //初始化this指向
        this.initBind();
        //throw捕获
        try{
            //执行传进来的函数
            executor(this.resolve,this.reject);  
        }catch(e){
            //throw抛错误直接走reject
            this.reject(e);
        }

    }
    initValue(){
       //初始化为pending等待状态
       this.promiseState = 'pending';
       this.promiseResult = null;
    }
    initBind(){
        //将resolve与reject中的this指向为MyPromise实例
        this.resolve = this.resolve.bind(this);
        this.reject = this.reject.bind(this);
    }


    resolve(value){
       //不是等待状态,说明已经成功或失败了,只有等待状态才会  resolve() || reject()
       if(this.promiseState != 'pending'){
          return;
       }
       //状态改为成功
       this.promiseState = 'fulfilled';
       this.promiseResult = value;

    }
    reject(reason){
        //不是等待状态,说明已经成功或失败了,只有等待状态才会  resolve() || reject()
        if(this.promiseState != 'pending'){
          return;
        }
        //状态改为失败
       this.promiseState = 'rejected';
       this.promiseResult = reason;
    }
    then(){

    }
}

再测试下:

let a = new MyPromise((resolve,reject)=>{
    resolve('成功!')
});

let b = new MyPromise((resolve,reject)=>{
    reject('失败!')
});

console.log(a);  // MyPromise {promiseState: "fulfilled" , promiseResult: "成功!"  }
console.log(b);  //MyPromise {promiseState: 'rejected', promiseResult: '失败!'}

没有问题,我长疏了口气,继续往下写去!马上开始写then了,也是开始变难了!

class MyPromise{
    constructor(executor){
        //初始化数据
        this.initValue();
        //初始化this指向
        this.initBind();
        //throw捕获
        try{
            //执行传进来的函数
            executor(this.resolve,this.reject);  
        }catch(e){
            //throw抛错误直接走reject
            this.reject(e);
        }

    }
    initValue(){
       //初始化为pending等待状态
       this.promiseState = 'pending';
       this.promiseResult = null;
    }
    initBind(){
        //将resolve与reject中的this指向为MyPromise实例
        this.resolve = this.resolve.bind(this);
        this.reject = this.reject.bind(this);
    }


    resolve(value){
       //不是等待状态,说明已经成功或失败了,只有等待状态才会  resolve() || reject()
       if(this.promiseState != 'pending'){
          return;
       }
       //状态改为成功
       this.promiseState = 'fulfilled';
       this.promiseResult = value;

    }
    reject(reason){
        //不是等待状态,说明已经成功或失败了,只有等待状态才会  resolve() || reject()
        if(this.promiseState != 'pending'){
          return;
        }
        //状态改为失败
       this.promiseState = 'rejected';
       this.promiseResult = reason;
    }
    then(onfulfilled,onrejected){
        //保证onfulfilled,onrejected都是函数,.then(res=>{},err=>{})参数是函数
        onfulfilled = typeof onfulfilled == 'function' ? onfulfilled : val=>val ;
        onrejected = typeof onrejected == 'function' ? onrejected : reason =>{ throw(reason) };

        //判断promiseState的状态 成功 失败 等待
        if(promiseState == 'fulfilled'){
            onfulfilled(this.promiseResult);
        }else if(promiseState == 'rejected'){
            onrejected(this.promiseResult);
        }else if(promiseState == 'pending'){

        }
    }
}

此时我想到了promise的链式调用,只有当成功或失败时,才会走.then()方法,比如Promise((resolve,reject)={ settimeout((...)=>,2000) }).then(...) 这种情况是2s后才执行.then,通过控制promiseState的状态,其实可以达到这种效果的

我在思考时,无意间看见了面试官的表情,他脸上写满了凝重,看来他也是在思考这个问题!

此时我们定义事件队列,只有,只有执行完上一个任务才会执行下一个,通过状态控制,pending说明是等待状态,直接就推到事件队列中,待执行


class MyPromise{
constructor(executor){
    //初始化数据
    this.initValue();
    //初始化this指向
    this.initBind();
    //throw捕获
    try{
        //执行传进来的函数
        executor(this.resolve,this.reject);  
    }catch(e){
        //throw抛错误直接走reject
        this.reject(e);
    }

}
initValue(){
   //初始化为pending等待状态
   this.promiseState = 'pending';
   this.promiseResult = null;
   //定义事件队列,里面都是待执行的事件
   this.onFulfilledCallBackList = [];
   this.onRejectedCallBacklist = [];
}
initBind(){
    //将resolve与reject中的this指向为MyPromise实例
    this.resolve = this.resolve.bind(this);
    this.reject = this.reject.bind(this);
}


resolve(value){
   //不是等待状态,说明已经成功或失败了,只有等待状态才会  resolve() || reject()
   if(this.promiseState != 'pending'){
      return;
   }
   //状态改为成功
   this.promiseState = 'fulfilled';
   this.promiseResult = value;

   //执行队列中的事件
   while(this.onFulfilledCallBackList.length){
       this.onFulfilledCallBackList.shift()(this.promiseResult);
   }

}
reject(reason){
    //不是等待状态,说明已经成功或失败了,只有等待状态才会  resolve() || reject()
    if(this.promiseState != 'pending'){
      return;
    }
    //状态改为失败
   this.promiseState = 'rejected';
   this.promiseResult = reason;

   //执行队列中的事件
   while(this.onRejectedCallBacklist.length){
        this.onRejectedCallBacklist.shift()(this.promiseResult);
   }

}
then(onfulfilled,onrejected){
    //保证onfulfilled,onrejected都是函数,.then(res=>{},err=>{})参数是函数
    onfulfilled = typeof onfulfilled == 'function' ? onfulfilled : val=>val ;
    onrejected = typeof onrejected == 'function' ? onrejected : reason =>{ throw(reason) };

    //判断promiseState的状态 成功 失败 等待
    if(this.promiseState == 'fulfilled'){
        onfulfilled(this.promiseResult);
    }else if(this.promiseState == 'rejected'){
        onrejected(this.promiseResult);
    }else if(this.promiseState == 'pending'){
        //等待状态,需要加入到事件队列
        this.onFulfilledCallBackList.push(onfulfilled);
        this.onRejectedCallBacklist.push(onrejected);
    }
}
}

测试一下:


new MyPromise((resolve,reject)=>{
     setTimeout(()=>{
        resolve('123');
     },3000)
}).then(res=>{
     console.log(res);
})//3s 后打印123 

此时面试官再看我,已经完全没有了起初那么轻蔑,换来的是客气,面试对我说,还要写下去吗,我已经认可你的实力了! 我不假思索的回答到:就差一点了!

现在就是.then的问题了,因为then本身会返回一个新的peomise,状态是由上一个promise决定的。

    分下面这几种情况:
    //1、如果返回值是promise对象,返回值为成功,新promise就是成功(x.then(resolve()))
    //2、如果返回值是promise对象,返回值为失败,新promise就是失败(x.then(reject()))
    //3、如果返回值非promise对象,新promise对象就是成功,值为此返回值
    // 4、返回失败的 通过try catch捕获

完整的代码:

class MyPromise {
    constructor(executor) {
        this.initValue();
        this.initBind();
        try {
            executor(this.resolve, this.reject);
        } catch (e) {
            this.reject(e)
        }
    }
    // 初始化参数信息
    initValue() {
        this.promiseState = 'pending';
        this.promiseResult = null;
        this.onFulfilledCallBackList = [];
        this.onRejectedCallBacklist = [];
    }
    // 初始化this指向
    initBind() {
        this.resolve = this.resolve.bind(this);
        this.reject = this.reject.bind(this);
    }
    resolve(value) {
        // 指定唯一状态,改变后,状态就是唯一的,fulfilled或者rejected就不改变了
        if (this.promiseState !== 'pending') {
            return;
        }
        this.promiseState = 'fulfilled';
        this.promiseResult = value;
        while (this.onFulfilledCallBackList.length) {
            this.onFulfilledCallBackList.shift()(this.promiseResult);
        }
    }
    reject(reason) {
        if (this.promiseState !== 'pending') {
            return;
        }
        this.promiseState = 'rejected';
        this.promiseResult = reason;
        while (this.onRejectedCallBacklist.length) {
            this.onRejectedCallBacklist.shift()(this.promiseResult);
        }
    }
    then(onfulfilled, onrejected) {
        // 保证参数必须是函数
        onfulfilled = typeof onfulfilled == 'function' ? onfulfilled : value => value;
        onrejected = typeof onrejected == 'function' ? onrejected : reason => { throw (reason) };

        let promise2 = new MyPromise((resolve, reject) => {
            if (this.promiseState === 'fulfilled') {
                // Promise.then异步任务
                setTimeout(() => {
                    // 错误捕获
                    try {
                        const x = onfulfilled(this.promiseResult);
                        if (x instanceof MyPromise) {
                            x.then(
                                value => resolve(value),
                                reason => reject(reason)
                            )
                        } else {
                            resolve(x)
                        }
                    } catch (e) {
                        reject(e)
                    }
                })
            } else if (this.promiseState === 'rejected') {
                setTimeout(() => {
                    try {
                        const x = onrejected(this.promiseResult);
                        if (x instanceof MyPromise) {
                            x.then(
                                value => resolve(value),
                                reason => reject(reason)
                            )
                        } else {
                            reject(x)
                        }
                    } catch (e) {
                        reject(e)
                    }
                })
            } else if (this.promiseState === 'pending') {
                this.onFulfilledCallBackList.push(onfulfilled);
                this.onRejectedCallBacklist.push(onrejected);
            }
        })
        return promise2
    }
}

测试一下:

let p = new MyPromise((resolve, reject) => {
    console.log('开始了!')
    resolve(12345)
}).then(res => {
    return new MyPromise((resolve, reject) => {
        setTimeout(() => {
            resolve(res)
        }, 3000)
    })
}).then(res => {
    console.log(res, '成功了!')
})

写罢,面试官露出满意的微笑,并告知我已经通过考核了,晚会HR会跟我沟通,我美滋滋的走出大楼,心情不错,觉得奢侈一把,喊个滴滴回家,等待消息 夜晚8点,我正在峡谷畅游,

    突然接到一个电话:
    喂,是XXX吗?
    是的,您是?
    哦,我是xxx的HR,您通过我们公司的面试啦,现在跟您谈下薪资情况。
    哦,是您啊,好的好的(暗中窃喜)。
    我们这一月3800,包一顿午饭,您看可以吗?
    。。。。。。

1676616243091.jpg