promise规范 手写promise

845 阅读6分钟

promise规范

promise states

promise有三种状态:pending 准备状态 resolve 成功 reject 失败

1 .pending

初始状态,一个promise再未被resolve和reject之前的状态都是该状态 ,该状态可以转变成fulfilled 或者rejected

  1. fulfilled 最终的不可变的状态 通过调用resolve实现 resolve中的回调必须拥有一个value的值(也就是then中必须有一个带有参数的回调)

3.rejected

最终的不可变的状态 通过调用reject实现 reject中的回调必须拥有一个reason的值(也就是catch中必须有一个带有参数的回调或者then的第二个方法——一个带有参数的回调函数)

then

promise应该提供一个then方法, 用来访问最终的结果, 无论是value还是reason.

promise.then(onFulfilled,onRejected)

1.参数要求

then中的两个参数都必须是函数类型 如果不是函数类型的参数则忽略 程序默认传参是函数类型 并且返回值是对应的value 或者reason

  1. onFulfilled

在promise变成fulfilled的时候,应该调用onFulfilled 参数为value 在fulfilled之前则不能进行调用 只能执行一次

  1. onRejected

在promise变成onRejected的时候,应该调用onRejected 参数为reason 在rejected之前则不能进行调用 只能执行一次

4 onFulfilled和onRejected应该都是微任务

用queueMicrotask(callback)实现

5 then方法可以被调用多次 运用数组存储onFulfilled和onRejected 适用于一下场景

promise.then(fn)
promise.then(fn)
promise.then(fn)
promise.then(fn)
promise.then(fn)

6.then返回的应该是一个promise对象 用于链式调用


promise2 = promise1.then(onFulfilled, onRejected);

onFulfilled或者onRejected的执行结果我们暂且定义为x,调用resolvePromise()如果onFulfilled或者onRejected执行异常我们通过reject抛出 如果不是函数 我们需要取promise1 中的值(value或者reason) 传递给下次链式调用的触发函数 value->fulfilled reson->rejected

7 resolvePromise resolvePromise作用:判断onFulfilled或者onRejected回调函数的类型和结果
7.1 如果x===promise2 则reject(new Error('同实例报错'))

7.2 如果 x 是一个promise的话 我们则需要继续调用x的then方法 将返回的值传入resolvePromise中 层层解刨 直到 x是一个基本类型

7.3 如果是一个object或者函数的话 let then = x.then. 如果 x.then 这步出错,那么reject掉 如果是一个函数的话then.call(x, resolvePromiseFn, rejectPromise) resolvePromiseFn 的 入参是 y, 执行 resolvePromise(promise2, y, resolve, reject); rejectPromise 的 入参是 r, reject(r). 如果 resolvePromise 和 rejectPromise 都调用了,那么第一个调用优先,后面的调用忽略。 如果调用then抛出异常e 如果 resolvePromise 或 rejectPromise 已经被调用,那么忽略 则,reject(error)

7.4 基本数据类型的话则resolve(x)

resolvePromise(promise2, x, resolve, reject)

实现

///手写promise
//定义promise中的三种状态
const   PENDING='pending'
const   FULFILLED= 'fulfilled'
const   REJECTED='rejected'
//重新设置一个status 的意义在于我们在status改变的时候去进行数组方法的执行,这样做的好处就是保证了我们的
//reject和resolve的函数只执行一种行为,遵循函数单一原则

class JKQPromise{
    FULFILLED_CALLBACK_LIST=[]
    REJECTED_CALLBACK_LIST=[]
    _status=PENDING
    constructor(fn){
        //初始默认值
        this.status=PENDING
        this.value=null
        this.reason=null
      //执行fn的方法 指定this的指向 
     try{
        fn(this.resolve.bind(this),this.reject.bind(this))
     }catch(e){
      this.reject(e)
     }
    }

    get status(){
        return this._status  //如果这里直接用this.status的话则直接造成死循环
    }
    set status(newStatus){
        this._status=newStatus
        //在改变状态的时候我们去执行回调数组中的方法
        switch(this.status){
            case  FULFILLED:
                this.FULFILLED_CALLBACK_LIST.forEach(callback=>{callback(this.value)})
            break;
            case REJECTED:
                this.REJECTED_CALLBACK_LIST.forEach(callback=>{callback(this.reason)})
                break;

        }
    }

    //修改promise中的状态
    //resolve
    resolve(value){
        console.log(value,'3331ss')
        if(this.status===PENDING){
          this.status=FULFILLED
          this.value=value
        }

    }
    //reject
    reject(reason){
        if(this.status===PENDING){
            this.status=REJECTED
            this.reason=reason
          }

    }
    //then方法   两个回调 成功的回调和失败的回调
    then(onFulfilled,OnRejected){
        //判断回调的方法类型 如果不是函数则应该被忽略 执行内部的默认   直接将ressolve中的value返回 实现穿透
     let  realFulfilled=this.isFunction(onFulfilled)?onFulfilled:value=>value
     let realRejected=this.isFunction(OnRejected)?OnRejected:reason=>reason
     //链式调用的原因 then方法返回的仍然是一个promise对象(新的)
     let promise2 =  new JKQPromise((resolve,reject)=>{
          //将传入进来的回调函数放在数组中便于状态改变的时候统一执行
   
     ///在链式调用的时候如果上一个promise执行错误 则下一个then就获取不到
     let fulfilledMicrotask=()=>{
       queueMicrotask(()=>{
        try{
            //resolve执行后的返回值
            let x= realFulfilled(this.value)
            this.resolvePromise(promise2,x,resolve,reject)
        }catch(e){
        //如果错误抛出错误
           reject(e)
        }
       })
      
    }
    let rejectedMicrotask=()=>{
        queueMicrotask(()=>{
            try{
                const x = realRejected(this.reason)
                this.resolvePromise(promise2,x,resolve,reject)
            }catch(e){
                reject(e)
            }
        })
      
       
    }
      switch(this.status){
        case  FULFILLED:
            fulfilledMicrotask()
        break;
        case REJECTED:
            rejectedMicrotask()
        
          break;
          case PENDING:
              //将成功或者失败状态下的回调函数添加到 对应的回调数组中
              this.FULFILLED_CALLBACK_LIST.push(onFulfilled)
              this.REJECTED_CALLBACK_LIST.push(OnRejected)
              break
    }
     })
     //返回promise对象 实现链式调用
    return promise2
    }
   // 对于回调x进行判断和处理
     resolvePromise(promise2,x,resolve,reject){
    if(promise2===x){
    ///证明是实例和返回的对象是一个东西则返回错误
      return reject(new Error('the same object'))

    }
     if(x instanceof JKQPromise){
         console.log(x)
        //如果是promise的实例的话  则继续重复调用   对于调用中获取到的值 在进行继续解析
        queueMicrotask(()=>{
            x.then((y)=>{
                ///通过循环调用的方式获取最后的基本类型的数据(详情看测试) 用于下一个链式调用
                this.resolvePromise(promise2,y,resolve,reject)
            },reject)

        })

    }else if(typeof x === 'object' || this.isFunction(x)){
          //空对象
          if(x === null){
             return  resolve(x)
          }
          let then  = null
          try {
            // 把 x.then 赋值给 then 
            then = x.then;
        } catch (error) {
            // 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
            return reject(error);
        }
       ///如果对象或者函数中存在then 并且then是个函数
        if(this.isFunction(then)){
        //只能执行一次
           let  called=false
           try{
             then.call(x,(y)=>{
                 if(called)return
                 called=true
                 //成功
                 this.resolvePromise(promise2,y,resolve,reject)
             },(r)=>{
             //失败
                 if(called)return
                 called=true
                 reject(r)
             })
           }catch(e){
              if(called) return
              //执行报错  则直接reject掉
              reject(e)
           }

        }else{
            //不是函数则直接执行resolve
            resolve(x)
        }
    
      }else{
          //直接执行resovle
          resolve(x)
      }

    }

    
    
     catch(OnRejected){
         //返回的是then的调用
         return this.then(null,OnRejected)

     }
   

    
    isFunction(params){
        return typeof params ==='function'
    }

//resolve 的直接调用
  static resolve(value){
      if(value instanceof JKQPromise){
         //如果value 是promise的实例的话 直接返回 实现链式调用
         return value
      }else{
          new JKQPromise((resolve,reject)=>{
              resolve(value)
          })
      }
  }

  static reject(reason) {
    return new MPromise((resolve, reject) => {
        reject(reason);
    });
    
    
    
  static all(arrays){
    return new MPromise((resolve,reject)=>{
        if(!Array.isArray(arrays)){
            throw new Error('不是数组')
        }
        let length =arrays.length
        let resolveArray=[]
        for(let i =0;i< length;i++){
           arrays[i].then(data=>{
                resolveArray.push(data)
                if(length==resolveArray.length){
                    //resove出去  外面通过then可以全部获取
                    resolve(resolveArray)
                }
            },reject)
            
        }
    })
       

    }
}
}

总结: 1.then方法返回的是一个新的promise 这个promise的初始状态是pending

2.当第一promise中的onFulfilled不是函数的时候其resolve的value或默认的传递给新创建的promise 以便于一下then使用 也就是说上一个then中的值会作为下一个then中的回调函数的参数使用(上一个promise then得返回才能使用)

3.resolvePromise(promise2,x,resolve,reject)就是对于传入x参数进行类型的判断,根据类型的不同执行逻辑不同 如果x是promise2实例 则reject(error) 如果是 JKQPromise的实例的话 则递归调用直到获取到 直到resolve出去为止 如果是object或者function的时候 内部有then方法且为函数的时候 调用then方法then.call(x,(y)=>{ //继续对y进行类型判断 直到resolve出去为止 this.resolvePromise(promise2, y, resolve, reject); }, (r) => {reject(r); })

  1. 链式调用 then中都返回的是新的promise对象 当第一个promise中执行resolve后 通过then可以获取到第一个resolve的值 then 返回的新的promise 会根据then的回调函数的返回值 去执行内部的类型判断 然后在决定当前promise的状态和值 5.链式调用用catch后边继续链式then的话then也可以执行 因为 catch进行了异常的处理,返回的也是promise对象 并且后面then中的value使用的是catch之前的值,注意:在链式调用中catch回调函数 如果抛出异常则状态是rejected 如果正常执行则状态是fulfilled reason被后续的catch所继续使用