从零手撕Promise,掌握Promise的实现原理(4)之then方法链式调用的初步实现

471 阅读3分钟

「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战」。

建议阅读前几篇文章

从零手撕Promise,掌握Promise的实现原理(1)之promise基本结构的实现 从零手撕Promise,掌握Promise的实现原理(2)之基础版本的promise实现 从零手撕Promise,掌握Promise的实现原理(3)之回调地狱是什么

回顾

我们已经完成了基出版本的promise,如下

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class Promise{
  constructor(executor){

    this.state = PENDING
    this.value = undefined
    this.reason = undefined
    //存放onFulfilled
    this.onResolvedCallbacks = []
    //存放onRejected
    this.onRejectedCallbacks = []
    const resolve = (value) => {
      if (this.state === PENDING) {
        this.value = value
        this.state = FULFILLED
        //promise实例状态改变后调用暂存的onFulfilled
        this.onResolvedCallbacks.forEach(fn => fn())
      }
    }

    const reject = (reason) => {
      if (this.state === PENDING) {
        this.reason = reason
        this.state = REJECTED
        //promise实例状态改变后调用的onRejected
        this.onRejectedCallbacks.forEach(fn => fn())
      }
    }
    try {
      //executor函数执行过程中出错,将会导致Promise失败
      executor(resolve,reject)
    } catch (error) {
      reject(error)
    }
  }
  then(onFulfilled, onRejected){
    if (this.state === FULFILLED) {
      onFulfilled(this.value)
    }

    if (this.state === REJECTED) {
      onRejected(this.reason)
    }

    if (this.state === PENDING) {
      //如果此时promise实例的状态还未确定,我们需要将onFulfilled与onRejected存起来,等到promise实例状态改变后再去调用
      this.onResolvedCallbacks.push(() => {
        onFulfilled(this.value)
      })
      this.onRejectedCallbacks.push(() => {
        onRejected(this.reason)
      })
    }

  }
}

Promisethen链调用机制

  • 通过上一篇回调地狱的介绍我们可以发现,promisethen链机制,可以让我们用同步代码的编写方式,去编写我们的异步代码,promisethen链机制也是promise实现的最核心的地方,接下来我们将根据Peomise A+来继续实现我们的Peomise

then方法返回普通值

    1. promise实例的then方法有两个参数,一个是成功后执行的回调(onFulfilled)一个是失败后执行的回调(onRejected),如果then的回调(成功的回调或者失败的回调)返回一个普通值(不是Promise,也不是抛出错误),则会将结果传递到下一次then的成功回调中。
    1. 因为then方法是链式调用的,因此then方法每次返回的都是一个Promise实例。
    1. 在执行onFulfilledonRejected的时候如果执行过程出现异常,那么会把这个异常抛出到下一次then的失败回调中去。
  • 代码实现如下:
then(onFulfilled, onRejected){

  let promise = new Promise((resolve, reject) => {
      
      switch(this.state){
        case FULFILLED:
            //执行回调的过程中,出现异常,那么会把这个异常抛出到下一次`then`的失败回调中去。
            try{
              let x = onFulfilled(this.value)
              resolve(x)
            } catch(e){
              reject(e)
            }   
            break
        case REJECTED:
            try{
              let x = onRejected(this.reason)
              resolve(x)
            } catch(e){
              reject(e)
            }   
            break
        default:
          this.onResolvedCallbacks.push(() => {
            try{
              let x = onFulfilled(this.value)
              resolve(x)
            } catch(e){
              reject(e)
            }
          })
          this.onRejectedCallbacks.push(() => {
            try{
              let x = onRejected(this.reason)
              resolve(x)
            } catch(e){
              reject(e)
            }
          })
      }
    
  })
  //返回一个 Promise
  return promise
} 
  • 至此我们已经完成了then方法的初步版本,我们可以初步测试一下

    let Promise = require('./promise/1.promise.js')
    
    let p = new Promise((resolve,reject) => {
        resolve('成功')
    })
    
    p.then(value => {
      console.log('value',value);
      return 10000000000000
    },reason => {
      console.log('reason',reason);
    }).then(value => {
      console.log('value',value);
    },reason => {
      console.log('reason',reason);
    })
    
  • 从打印结果可以看出我们的then方法已经满足返回普通值的链式调用了

    11-05-1.png 传送门

从零手撕Promise,掌握Promise的实现原理(1)之promise基本结构的实现

从零手撕Promise,掌握Promise的实现原理(2)之基础版本的promise实现 从零手撕Promise,掌握Promise的实现原理(3)之回调地狱是什么

后续文章每天会持续完成