手撕Promise,深度掌握其原理

promise 是一个为了解决请求回调地狱的解决方式 他的实质是一个类
首先来说一下promise的简单用法

let promise = new Promise((resolve,reject)=>{
   resolve(666)
})
promise.then(res=>{
   console.log(res)//666
})
  • promise 被构造时接收一个立即执行函数,该函数有两个参数,那就是resolve和reject,且resolve或reject所抛出的值会被then所接收。
  • 当promise调用resolve或者reject的时候 ,then里面的方法才会被执行,这就相当于一个发布订阅模式
  • promise 有三种状态, 分别是 等待、成功和失败。初始状态为等待,不管成功还是失败 都是不可逆的 一旦成功就不再会失败(反之一样)

Promise构造函数

//定义三种状态
 const ENUM = {
      PENDING:'PENDING',
      FULFILLED:'FULFILLED',
      REJECTED:'REJECTED'
}

class myPromise {
      constructor(executor) {
              this.status = ENUM.PENDING;//初始状态
              this.value = undefined; //用于保存resolve所抛出去的值  (tips:我们发请求得到的值会resolve出去,便于then中接收使用)
              this.reason = undefined;//用于保存reject所抛出的值
              this.onFulfilledCallbacks = [];//用于存储then中的成功回调函数,当promise状态改变会触发
              this.onRejectedCallbacks = [];//存储失败回调
              const resolve = value => {
                      if(this.status === ENUM.PENDING) { // 只有等待态才可改变状态
                            this.status = ENUM.FULFILLED;
                            this.value = value;
                            this.onFulfilledCallbacks.forEach(fn=>fn())
                      }
              }
              const reject = reason => {
                      if(this.status === ENUM.PENDING){
                            this.status = ENUM.REJECTED;
                            this.reason= reason;
                            this.onRejectedCallbacks.forEach(fn=>fn())
                      }
              }
              //防止执行报错
              try{
                    executor(resolve,reject)
              }catch(e){
                      reject(e)
              }

      }
}

  • then方法接收两个函数 ,第一个为成功回调,第二个为失败回调,promise会先将两个方法存在内存中,当状态改变后就会触发对应的方法执行
  • then可以链式调用,也就是then还会返回一个新的promise,且两个promise不能是同一个,否则会循环引用

promise.then 在调用的时候会发生的情况

//1.链式调用
let promise = new Promise((resolve,reject)=>{
   resolve(666)
})
promise.then().then().then(res=>console.log(res)//666)
//2.then链式调用传参的问题
promise.then(res=>{
   console.log(res)//666
   return  '这是then的返回值'
}).then(res=>{
    console.log(res)// 会输出: '这是then的返回值'
})
//如此说明 每次调then都会返回一个新的promise,且promise会默认resolve上一个回调函数的返回值
//3. 回调函数中返回了一个promise
promise.then(res=>{
   console.log(res)//666
   return  new Promise((resolve,reject))=>{
               resolve('新的promise的value')
   }
}).then(res=>{
//注意: 这里输出的是上一次返回的promise中resolve的值,说明then传的回调函数在执行过程中会解析其返回值,如果是个promise就会将他执行 直到返回非promise值为止
    console.log(res)// 会输出: '新的promise的value'  
})
//4.then延迟添加回调方法
let promise = new Promise((resolve,reject)=>{
   resolve(666)
})
settimeout(()=>{promise.then(res=>console.log(res)//666)},1000)

实现解析then回调函数的返回值的方法

const resolvePromise = (x,promise2,resolve,reject)=> {
       //当x(返回值)是一个promise 且更他上一个promise是同一个时 直接return 防止循环引用
       if(x === promise2) {
             reject(new TypeError('循环引用'))
       }
       //判断是否是一个promise  不是则直接resolve,
       if(x instanceof myPromise){
            let called;//定义变量 做节流功能
            try{
                x.then(res=>{
                      if(called)return;
                      called = true;
                      resolvePromise(res,promise2,resolve,reject)//递归调用 直到不是promise为止
                },err=>{
                   if(called)return;
                      called = true;
                      reject(err)
               })
            }catch(e){
                if(called) return;
                called = true;
                 reject(e)
            }
       }else{
             resolve(x)
       }
}

实现then方法(参数只允许是函数 不传就默认赋值 以便链式调用)

then(onFulfilled,onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
    onRejected= typeof onRejected=== 'function' ? onRejected: () => {throw err};
    let promise2 = new myPromise((resolve,reject)=>{
            if(this.status === ENUM.FULFILLED){// 防止 then方法延迟添加回调函数而状态先发生改变的情况
                   // 利用定时器来实现promise的异步原理。同时可以拿到自身
                  settimeout(()=>{
                         try{
                              let x = onFulfilled(this.value)//当状态改变后 拿到resolve中的value
                              resolvePromise(x,promise2,resolve,reject)
                         }catch(e){
                               reject(e)
                         }
                  })
            }
            if(this.status === ENUM.REJECTED) {//同上  防止状态先发生改变什么都不做
                 settimeout(()=>{
                      try{
                          let x = onRejected(this.reason);
                          resolvePromise(x,promise2,resolve,reject)
                      }catch(e){
                             reject(e)
                      }
                 })
            }
             // 在等待状态时 将成功回调跟失败回调放到内存中  等状态发生改变就执行
            if(this.status === ENUM.PENDING){
                    this.onFulfilledCallbacks.push(()=>{
                        settimeout(()=>{
                             try{
                                    let x = onFulfilled(this.value)
                                    resolvePromise(x,promise2,resolve,reject)
                              }catch(e){
                                    reject(e)
                              }
                        })
                    })
                    this.onRejectedCallbacks.push(()=>{
                             settimeout(()=>{
                                  try{
                                          let x = onRejected(this.reason);
                                          resolvePromise(x,promise2,resolve,reject)
                                   }catch(e){
                                           reject(e)
                                  }
                              })
                    })
            }
    })
     //注意 : 不要忘记 把 promise 返回出去
    return promise2

}

到这里 一个promise就完成了,当然 promise 还有一些其他的原型方法和静态方法,实例方法包括(catch,finally),静态方法包括(all,race,resolve,reject)。这些方法都是可以基于实现的这个promise去实现。在这里就不补充了。

以上都是个人的理解,如果有错误的地方希望大佬们能指点一二。

你可能感兴趣的:(手撕Promise,深度掌握其原理)