手写Promise笔记(上)

手写Promise感觉还是挺常见的,这里记录下自己构建整个Promise的过程,主要参考的是后盾人Promise教程,记录下看完之后的笔记和个人的思考。

Promise的基本知识

  1. Promise包含pending等待,fulfilled成功,rejected拒绝三种状态,当时pending状态的时候可以转换为成功/拒绝状态,并且转换后不能再转换。
  2. 一个promise必须有一个then方法,then方法接受两个参数promise.then(onFulfilled,onRejected),这里onFulfilled方法是成功状态的处理函数,onRejected方法是失败状态的处理函数。
  3. 为了实现链式调用,then方法也要返回一个promise

手写Promise

不多说直接放全部代码,具体笔记和理解在备注中,部分的笔记图片可以看代码后的图片

class myPromise {
   // 声明3个状态,分别为pending等待/resolve解决/reject拒绝
   static PENDING = 'pending'
   static FULFILLED  = 'fulfilled'
   static REJECT = 'rejected'
   constructor (executor) {
      // executor为执行者
      // 一开始是等待状态
      this.status = myPromise.PENDING
      this.value = null
      // 用于保存需要执行的函数
      this.callbacks = []
      // 这里使用try..catch的原因是如果在promise中出现了错误信息的情况,就直接丢给reject来处理
      try {
         // class内this遵循严格模式,此处的this是指向的window
         // 使用bind认为干预this指向
         executor(this.resolve.bind(this),this.reject.bind(this));
      } catch (error) {
         // 把错误信息给reject来处理
         this.reject(error)
      }
   }
   // 类方法
   resolve(value) {
      // 这里需要增加一个判断,如果当前Promise的状态为pending的时候,才能进行状态更改和处理
      if(this.status === myPromise.PENDING) {
        // 执行类方法的时候就要改变Promise的状态和值
        this.status = myPromise.FULFILLED
        this.value = value
        setTimeout(() => {
           // 这里还是要处理为异步任务,如果promise内出现异步处理的函数内还有同步任务
           // 那么需要先解决同步任务,再进行Promise的状态改变和处理
           // 可以结合后文的图片来理解[图:Pending状态下的异步处理]
           this.callbacks.map(callback => {
              // 这里应该这样理解,当状态异步改变的时候,先把then里面的方法保存起来,然后等状态改变了
              // 就从之前保存的函数中,拿到then里面的对应方法执行
              callback.onFulfilled(value)
         })
        })
      }
   }
   reject(reason) {
      if(this.status === myPromise.PENDING) {
         this.status = myPromise.REJECT
         this.value = reason
         setTimeout(() => {
            this.callbacks.map(callback => {
               // 这里用map应该是存入的时候使用了数组push,这里map会对每个数组数据进行处理,这里数组只有1个数据
               // 所以是执行1次,存入的又是一个对象所以可以用callback.onRejected获取对应函数
               callback.onRejected(reason)
            })
         })
       }
   }
   // then方法的实现
   then(onFulfilled,onRejected) {
      // 两个函数不是必须传入的,例如会出现then(null,onRejected)的情况
      if(typeof onFulfilled !== 'function') {
         // 自己封装一个空函数上去
         // 同时返回value的值,由此来实现穿透
         onFulfilled = () => {return this.value}
      }
      if(typeof onRejected !== 'function') {
         // 自己封装一个空函数上去
         onRejected = () => {return this.value}
      }
      // 这里是返回一个全新的promise,是为了让then支持链式调用
      // 将返回的Promise进行保存用于之后返回判断
      let promise =  new myPromise((resolve,reject) => {
         if(this.status === myPromise.PENDING) {
            // 这里是等待状态,在promise内部的函数是异步执行的,例如过多少秒之后才解决,
            // 那么我们手写的Promise就应该在pending状态下,保存需要执行的函数.
            // 异步改变状态的时候,会先来到这里保存函数
            this.callbacks.push({
               // 这里将保存的函数进行了一次包装,如果异步then中出现了错误,也会全部交给onRejected来处理
               onFulfilled: value => {
                  this.parse(promise,onFulfilled(value),resolve,reject)
                  // try {
                  //    // 这里的更改主要是针对Promise的内部函数的异步处理
                  //    let result = onFulfilled(value)
                  //    // 通过instanceof来判断result是否是通过myPromise实现的,从而确定是否是返回的Promise
                  //    if (result instanceof myPromise) {
                  //       // 如果是Promise的话,目的还是要改变Promise的状态,并且返回值
                  //       // 此时 result 是一个Promise
                  //       // 这里相当于重新执行了一次返回的Promise,递归
                  //       result.then(resolve,reject)
                  //    } else {
                  //       // 普通值直接返回
                  //       resolve(result)
                  //    }
                  // } catch (error) {
                  //    // then的异步处理中出现error就交给onRejected处理
                  //    // 同时这里的处理函数从onRejected改为reject,相当于把错误代码交给了
                  //    // 最后一个then来处理
                  //    reject(error)
                  // }
               },
               onRejected: reason => {
                  this.parse(promise,onRejected(reason),resolve,reject)
               },
            })
         }
         // 这里判断状态,必须是解决状态的情况才会执行onFulfilled函数,否则会出现状态没改变也执行的情况
         if(this.status === myPromise.FULFILLED) {
            // 使用setTimeout将then中的处理变成异步方法,这样才能符合正常promise的运行顺序
            // 这时这些代码不会立即执行,而是进入下一个loop中
            // 这里有点小问题,是setTimeout是宏任务,和自带promise相比,这个会比自带的then晚执行
            setTimeout(() => {
               // 因为链式调用把之前的值保存,然后传递给下一个then
               // 函数要是运行了就是把值传递,没有就是传递函数
               this.parse(promise,onFulfilled(this.value),resolve,reject)
            }, 0)
         }
         if(this.status === myPromise.REJECT) {
            setTimeout(() => {
               this.parse(promise,onRejected(this.value),resolve,reject)
            }, 0)
         }
      })
      return promise
   }
   // 代码复用
   parse(promise,result,resolve,reject) {
      if(promise === result) {
         // 这里的判断用于限制Promise.then不能返回自身
         throw new TypeError('aaa')
      }
      // 使用try..catch也是为了捕获then中出现的错误,只有写了catch才会有错误信息输出
      try {
           // 这里的更改主要是针对Promise的内部函数的异步处理
           // 通过instanceof来判断result是否是通过myPromise实现的,从而确定是否是返回的Promise
           if (result instanceof myPromise) {
              // 如果是Promise的话,目的还是要改变Promise的状态,并且返回值
              // 此时 result 是一个Promise
              // 这里相当于重新执行了一次返回的Promise,递归
              result.then(resolve,reject)
           } else {
              // 普通值直接返回
              resolve(result)
           }
        } catch (error) {
           // then的异步处理中出现error就交给onRejected处理
           // 同时这里的处理函数从onRejected改为reject,相当于把错误代码交给了
           // 最后一个then来处理
           reject(error)
        }
   }
   // resolve静态方法
   static resolve(value) {
      // 主要还是返回一个Promise
      return new myPromise((resolve,reject) => {
         //也是需要判断传入的是不是Promise
         if (value instanceof myPromise) {
            // 如果传入的是Promise,那么状态就和传入的Promise一样
            value.then(resolve,reject)
         } else {
            // 这种是原生状态,普通值直接返回
            resolve(value)
         }
      })
   }
   // reject静态方法实现
   static reject(value) {
      // 主要还是返回一个Promise
      return new myPromise((resolve,reject) => {
            reject(value)
         })
   }
   // all静态方法,都成功才成功,返回的还是Promise
   static all(promises) {
      return new myPromise((resolve,reject) => {
         const values = []
         promises.forEach(promise => {
            promise.then(
               value => {
                  // 每次成功就保存一次值
                  values.push(value)
                  if(values.length === promises.length) {
                     // 如果存入结果的数组长度等于传入promise的数组长度,那么就相当于所有的Promise都是成功的
                     resolve(values)
                  }
               },
               reason =>{
                  // 任何一个传入的Promise的状态为reject的话就改变返回的all的promise的状态
                  // 上面的resolve就不会继续走了
                  reject(reason)
               })
         })
      } )
      
   }
   // race静态方法,谁快用谁,不管成功还是失败,返回的也是Promise
   static race(promises) {
      return new myPromise((resolve,reject) => {
         promises.map(promise => {
            promise.then(
               value => {
                  // 状态只改变一次,所以直接使用就可以
                  resolve(value)
               },
               reason =>{
                  reject(reason)
               }
            )
         })
      })
   }
}

这里需要输出的结果是taec-aaa-解决,但是如果把resolve内处理成异步的话输出的结果就是taec-解决-aaa,setTimeout内是全部当做同步任务处理。

Pending状态下的异步处理

then支持链式操作的前提是之前的then返回一个promise即可。而且then返回的Promise的状态都是成功的。
then链式调用

如果处理过程中发生,错误那么会要把错误信息传递给最后一个then的reject来处理,所以在返回的时候,所有的错误处理函数都用的是reject()
reject的修改

then链式调用错误处理

可正常接收到抛出的错误

then穿透.then 或者 .catch 的参数期望是函数,传入非函数则会发生值穿透。
例如:

Promise.resolve(1)
  .then(function(){return 2})
  .then(Promise.resolve(3))
  .then(console.log) //    2

then穿透实现

实现穿透验证resolve

实现穿透验证reject

then返回Promise需要将返回的Promise重新执行,通过instanceof来判断返回的值是否是通过手写的myPromise来实现的,如果是就执行一遍返回的Promise的then函数,那么就会获取到值,如果不是就直接执行并且返回值,核心是递归调用了。
返回Promise验证

resolve/reject静态方法实现,使用static关键字,也是分传入的是Promise和普通值两种情况
静态方法实现

promise.all方法Promise.all([p1,p2]).then(value => {console.log(value)}),需要p1、p2两个都为成功才能获取到数据,否则就不行。
all方法测试

promise.race方法,几个Promise谁先完成就先用谁,状态只改变一次。
race方法测试

你可能感兴趣的:(手写Promise笔记(上))