手写promise 由简入深

86 阅读2分钟

碎碎念,一直没手写过promise,看笔记注释少总理解不上去,看了后盾人的视频终于敲下来一遍,但也不完整,

原生promise

new Promise((resolve,reject) => {
...一些同步执行的代码...
resolve(value)或 reject(reason);
}).then(
 value => {},
 reason => {}
)

手写思路

promise对象,有三种状态,内部通过resolve,reject改变状态,可以调用then方法处理返回值

简易版

class Prms{
// promise对象的三个状态
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';

constructor(executor){
   this.status = Prms.PENDING; //初始状态为pending
   this.value = null; // promise的返回值,即resolve(value), 会传给then方法
   
   this.callbacks = []; //以后要执行的函数  问题四
   
   // 对应的是传给new Promise的函数,即(resolve,reject)=>{...;resolve()/reject()}
   executor(this.resolve, this.reject) //下面问题一
}

resolve(value){
   this.status = Prms.FULFILLED; //改变promise的状态为成功
   this.value = value; //获取返回值,resolve(value)
}

reject(reason){
   this.status = Prms.REJECTED;
   this.value = reason; 
}

then(onFulfilled, onRejected){ // then方法中接受2个函数,分别对成功/失败情况做处理
    if(this.status === Prms.FULFILLED){ //状态改变后才会执行then方法
       onFulfilled(this.value)
    }
    if(this.status === Prms.REJECTED){
       onRejected(this.value)
    }
}
}

问题一:executor内部同步的代码可能有报错,需要捕获,并且this需绑定

    try {
        executor(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
        this.reject(error)
    }

问题二:promise对象只可修改一次,之后访问也不会再改变

    resolve(value){
       if(this.status == Prms.PENDING){ //即只能从pending=>fulfilled / pending=>rejected
          this.status = HD.FULFILLED;
          this.value = value;
       }
    }
    reject(reason)同理
   

问题三:.then是微任务,需要在同步代码后面执行

例如

  let p = new Promise((resolve,reject)=>{
      resolve(promise成功);
   }).then(value=>{console.log(value)});
   console.log('aaaa');

应该是先打印aaaa, 然后再打印promise成功;

  then(onFulfilled, onRejected){
    if(this.status === Prms.FULFILLED){
       setTimeOut(()=>{
         onFulfilled(this.value)
       })   
    }
    if(this.status === Prms.REJECTED){ //同上
       onRejected(this.value)
    }
}

问题四:new promise后会直接调用then方法,但这时状态可能还没改变

   new Promise(()=>{
     setTimeout(()=>{
       resolve('aaa');
     })
   }).then(), 这时promise状态还是pending,
  1. .then方法需增加pendging状态的处理

    if (this.status === HD.PENDING) { // 把状态改变后要执行的函数放进callbacks里
           this.callbacks.push({
               onFulfilled,
               onRejected
           })
    }
    

    2.resolve,reject方法也需执行相应函数

    resolve(value){
     this.status = Prms.FULFILLED;
     this.value = value; 
     this.callbacks.map(callback => {
        callback.onFulfilled(value)
     })
     }
    reject相同
    

问题五: aaa要先打印,然后才是解决。then是异步任务

   new Promise(()=>{
      setTimeOut(()=>{
           resolve('解决');
           console.log('aaaaa')
       })   
   }).then(value => console.log(value )) 

resolve/reject方法需要处理,回调函数放入settimeOut里,

 resolve(value){
      this.status = Prms.FULFILLED;
      this.value = value; 
      setTimeOut(()=>{ 
        this.callbacks.map(callback => {
           callback.onFulfilled(value)
        })
      })
   }    

问题六:.then可以链式操作,因为.then返回的也是一个promise

  new Promise((resolve,reject)=>{ resolve(成功)})
  .then(value=>{ then1 }, reason=>{})
  .then(value=>{ then2 },reason=>{})
  promise状态改变,then1获取成功/失败,then2都是成功

修改then方法

   if(this.status == Prms.FULFILLED){
      setTimeout(()=>{
        try {
           let result = onFulFilled(this.value);
           resolve(result);
        } catch (error){
           reject(error)
        }
      })
   }
   pending,rejected状态同样
   

问题七:then方法可能返回一个promise对象

   new Promise((resolve,reject)=>{})
   .then(value=>{
       return new Promise((resolve, reject)=>{ resolve('then返回promise对象')})
    }).then(......)

then方法需要对返回值进行判断

    if(this.status == Prms.FULFILLED){
      setTimeout(()=>{
        try {
           let result = onFulFilled(this.value);
           if(result instanceof Prms){
              result.then(
                 value => resolve(value);
                 reason => reject(reason)
              ) //返回的promise对象状态改变也要先调then方法
           }else{
              resolve(result);
           }
        } catch (error){
           reject(error)
        }
      })
   }
   pending,rejected状态同样