今天教你手写 Promise (一)

122 阅读4分钟

大家好,我是北妈

今天我们来聊聊常见的前端手写功能之Promise\

首先我们来聊聊要实现的功能:

1、Promise就是一个类,在执行类的时候,需要传递一个执行器(函数)进去,执行器会立刻执行

2、Promise有三种状态,分别为 等待 pending 成功 fulfilled 失败 rejected

pending => fulfilled || pending => rejected

状态一旦确定就不能改变

3、resolve和reject是用来更改状态的

resolve : fulfilled

reject : rejected

4、then方法内部做的事情就是判断状态 如果状态是成功 调用成功的返回函数 如果状态是失败 调用失败的回调函数 then方法是被定义在原型对象中的

5、then成功回调有一个参数,表示成功之后的值,then失败回调有一个参数,表示失败的原因

6、同一个promise对象下面的then方法是可以被调用多次的,then方法是可以链式调用的,后面的then方法回调函数拿到的值是上一个then方法的回调函数的返回值

确定功能后呢,接下来我们就要开始写代码了

const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise{
    constructor (executor) {
         try { // 尝试调用执行器            
         executor(this.resolve,this.reject)        
         } catch(e) { // 调用失败            
         this.reject(e)        
     }
 }
    // Promise 状态初始化为等待
    status = PENDING;
    // 成功之后的值
    value = undefined;
    // 失败的原因
    reason = undefined;
    // 成功的回调函数存放的数组
    successCallback = [];
    // 失败的回调函数存放额数组
    failCallback = [];
    resolve = value => {
        // 如果状态不是等待 阻止程序向下执行
        if(this.status !== PENDING) return
        // 更改状态为成功
        this.status = FULFILLED
        // 保存成功之后的值
        this.value = value
        // 成功回调存在 调用成功回调方法
        // this.successCallback && this.successCallback(this.value)
        // 因为then是可以多次调用的
        // this.successCallback.shift(),截取数组中的第一个元素并返回,会改变原数组
        while(this.successCallback.length) this.successCallback.shift()(this.value)
   }
   reject = reason => {
       if(this.status !== PENDING) return
       // 更改状态为失败
       this.status = REJECTED
       // 保存失败的值
       this.reason = reason
       // 成功回调存在 调用成功回调方法
       // this.failCallback && this.failCallback(this.value)
       while(this.failCallback.length) this.failCallback.shift()(this.value)
   }
   then(successCallback, failCallback){
       // 当没有成功回调时,将value值往下传递
       successCallback = successCallback ? successCallback : value => value;       
       // 当没有失败回调时,抛出异常
       failCallback = failCallback ? failCallback : reason => { throw reason };        
       // 创建一个新的 Promise对象
       let promise2 = new MyPromise((resolve, reject)=>{
            // 判断状态            
            if(this.status === FULFILLED){
                setTimeout(()=>{     
                    try {
                      // 定义 val接收成功回调的返回值
                      let x = successCallback(this.value);
                       // resolve(val)
                       // 判断val的值是一个普通值,还是promise对象,          
                       // 如果是普通值,直接调用resolve
                       // 如果是promise对象,查看promise对象返回的结果       
                       // 再根据promise对象返回的结果,决定调用resolve还是reject
                       resolvePromise(promise2, x, resolve, reject)
                   } catch(e) {
                       reject(e)
                   }    
                },0)
             }else if(this.status === REJECTED){  
                setTimeout(()=>{
                    try {
                        // 定义 val接收成功回调的返回值
                        let x = failCallback(this.reason)
                        // resolve(val)
                        // 判断val的值是一个普通值,还是promise对象,
                        // 如果是普通值,直接调用resolve
                        // 如果是promise对象,查看promise对象返回的结果
                        // 再根据promise对象返回的结果,决定调用resolve还是reject
                        resolvePromise(promise2, x, resolve, reject)
                   } catch(e) {
                       reject(e)
                   }
                },0)
             }else{ 
                // 当异步改变状态时,此时状态为 pending,将成功或失败回调缓存起来                
                // 每次调用 then方法 ,都会缓存一个回调
                this.successCallback.push(() => {
                    setTimeout(()=>{
                        try {
                            // 定义 val接收成功回调的返回值
                            let x = successCallback(this.value);
                            // resolve(val)
                            // 判断val的值是一个普通值,还是promise对象,
                            // 如果是普通值,直接调用resolve 
                            // 如果是promise对象,查看promise对象返回的结果     
                            // 再根据promise对象返回的结果,决定调用resolve还是reject
                            resolvePromise(promise2, x, resolve, reject)
                        } catch(e) {
                            reject(e)
                        }
                    },0)
                })
                this.failCallback.push(() => {
                    setTimeout(()=>{                        
                        try {                            
                            // 定义 val接收成功回调的返回值                           
                            let x = failCallback(this.reason)
                            // resolve(val)
                            // 判断val的值是一个普通值,还是promise对象,
                            // 如果是普通值,直接调用resolve
                            // 如果是promise对象,查看promise对象返回的结果
                            // 再根据promise对象返回的结果,决定调用resolve还是reject
                            resolvePromise(promise2, x, resolve, reject)
                        } catch(e) {
                            reject(e)
                        }
                    },0)
               })          
             }           
           })    
           // 返回一个 Promise对象
           return promise2;             
      }                  
      catch(failCallback){ 
          return this.then(undefined, failCallback)    
      }
      finally(callback){        
          // 无论成功或失败都要执行        
          return this.then(value=>{            
              return MyPromise.resolve(callback()).then(() => value)
          },reason => {  
              return MyPromise.resolve(callback()).then(() => {throw reason})  
          }) 
      }
      static all(array){
          let result = []
          let index = 0
          // 由index判断是否执行完所有代码,并将数据添加进result中了        
          return new MyPromise((resolve, reject) => {
              // 由addData方法像 result 中添加数据            
              function addData(key, val){
                  result[key] = val
                  index ++
                  if(index == array.length){
                  resolve(result)
              }
          }
          array.forEach((item,index) => {
              if(item instanceof MyPromise){
                  item.then(val => addData(index,val), 
                  reason => reject(reason))
              }else{
                  addData(index,item)
              }
          })
      })
  }
  static resolve(val){
      // promise对象直接原样返回        
      if(val instanceof MyPromise) return val;
      // 数值类型将其作为一个新的promise对象的返回值返回        
      return new MyPromise(resolve => resolve(val))
  }
}
function resolvePromise(promise2, x, resolve, reject){
    if(promise2 === x){        
        // console.log('传入了同一个promise');
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));    
    }    
    if(x instanceof MyPromise){
        // promise对象        
        // x.then(value => resolve(value), reason => reject(reason))       
        // 优化为:        
        x.then(resolve, reject)    
    }else{        
        // 普通值       
        resolve(x)    
    }
}

| 结语

我是北妈, 一个就怕你们吃亏的互联网型男,我在纷杂的网络和现实世界建立了一个桃花岛,希望和朋友们一起修炼进化,共同提升。欢迎入岛。-->沸点