手写Promise的基本实现

128 阅读4分钟

一、Promise的理解和使用

Promise是ES6新增的一种语法,是解决异步的一种方案。Promise是一种构造函数,利用Promise对象可以用来封装一个异步操作并且返回其获取的成功或者失败的结果值。

Promise的特点和优缺点: Promise有三种状态,分别是:pending、resolved、rejected,但是状态一经改变就无法再次修改。

二、分析官方的Promise

const p = new Promise((resolve, reject) => {
  resolve('success');
  reject('error');
})
p.then(
  (res) => {
    console.log(res);
  },
  (err) => {
    console.log(err);
  }
)

p调用then方法,then方法接收两个回调函数作为参数。在这里的代码只会打印success,因为promise的状态一旦由pending的状态改变了之后就无法再次进行改变。

上述代码当执行到resolve('success')后就会来到then的第一个回调函数,状态由pending转变为resolved(或者是fulfilled),如果是执行reject('error')就会来到第二个回调函数,状态由pending转变为rejected。

三、手写Promise的基本实现和代码解析

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

首先,我们现在全局定义Promise的三种状态,分别是pending、resolved、rejected。然后我们开始初步构思Promise实现原理,代码以及代码解析如下:

function MyPromise(fn) {//Promise接收的是一个函数,所以在这里定义一个fn
  //这里是解决一下this的指向
  const that = this
  //状态 函数执行的时候默认的初始状态就是pending
  that.state = PENDING 
  //用这个value来承接传递给resolve和reject函数的参数
  that.value = null
  
  //下面的两个就是函数 接收一个参数 状态要变更
  function resolve(val) {
  
  //因为状态一经更改就无法改变,所以在这里要放一个if判断
  //这样可以使得resolve和reject方法不会被一起触发
    if (that.state == PENDING) {
      that.state = FULFILLED
      that.value = val
    }
  }
  function reject(val) {
    if (that.state == PENDING) {
      that.state = REJECTED
      that.value = val
    }

  }
  
  //这里的操作就是捕获人为的代码逻辑错误,完善代码可行度
  try {
    fn(resolve, reject)
  } catch (err) {
    reject(err) //变更状态 捕获错误
  }
}

接下来要构思Promise后面接的then方法,因为构造一次Promise对象就可以直接使用then方法,所以在写then方法的时候应该把这个方法写在Promise的原型上,然后再对上述的初步Promise实现代码进行完善。代码以及代码解析如下:

//then方法接收两个回调函数
MyPromise.prototype.then = function (onFulfilled, onRejected) {
  //原型上的this和构造函数的this保持一致
  const that = this
  //判断放进来的是不是一个函数
  //如果是函数的话就是函数本身,如果不是的话就生成
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
  onRejected = typeof onRejected === 'function' ? onRejected : r => { throw r }
  //根据变更的状态来判断触发的是哪一个回调函数
 
  if (that.state === FULFILLED) {
  //逻辑与手写的Promise中的resolve和reject方法保持一致
    onFulfilled(that.value)
  }
  if (that.state === REJECTED) {
    onRejected(that.value)
  }
  //Promise后面可以接很多个then方法
  //后续的两个状态没办法触发,状态还是pending状态,所以我们先存起来
  if (that.state === PENDING) {
    that.resoveledCallBacks.push(onFulfilled)
    that.rejectedCallBacks.push(onRejected)
  }

}

因为Promise后面可以接很多个then方法,所以我们在MyPromise函数上定义两个数组来接收没有触发的状态。往后都是利用resolve调用来触发状态变更得到结果,所以部分代码更改如下:


function MyPromise(fn) {
  const that = this
  that.state = PENDING //状态 默认就是pending
  that.value = null
  //用数组因为后面不停地.then
  that.resoveledCallBacks = []
  that.rejectedCallBacks = []

  function resolve(val) {//这两个就是函数 接收一个参数 状态要变更
    if (that.state == PENDING) {
      that.state = FULFILLED
      that.value = val
      //往后都是用resolve来触发
      that.resoveledCallBacks.map(cb=>{
        cb(that.value)
      })
    }
  }
  function reject(val) {
    if (that.state == PENDING) {
      that.state = REJECTED
      that.value = val
      that.rejectedCallBacks.map(cb=>{
        cb(that.value)
      })
      
    }

  }
 }

四、完整代码展示


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

MyPromise.prototype.then = function (onFulfilled, onRejected) {
  const that = this//原型上的this和构造函数的this保持一致
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v//判断放进来的是不是一个函数
  onRejected = typeof onRejected === 'function' ? onRejected : r => { throw r }//判断放进来的是不是一个函数
  if (that.state === FULFILLED) {
    onFulfilled(that.value)
  }
  if (that.state === REJECTED) {
    onRejected(that.value)
  }
  if (that.state === PENDING) {
    //两个状态没办法触发,先存起来
    that.resoveledCallBacks.push(onFulfilled)
    that.rejectedCallBacks.push(onRejected)
  }

}


function MyPromise(fn) {
  const that = this
  that.state = PENDING //状态 默认就是pending
  that.value = null
  //用数组因为后面不停地.then
  that.resoveledCallBacks = []
  that.rejectedCallBacks = []

  function resolve(val) {//这两个就是函数 接收一个参数 状态要变更
    if (that.state == PENDING) {
      that.state = FULFILLED
      that.value = val
      //往后都是用resolve来触发
      that.resoveledCallBacks.map(cb=>{
        cb(that.value)
      })
    }
  }
  function reject(val) {
    if (that.state == PENDING) {
      that.state = REJECTED
      that.value = val
      that.rejectedCallBacks.map(cb=>{
        cb(that.value)
      })
      
    }

  }
  try {
    fn(resolve, reject)
  } catch (err) {
    reject(err) //变更状态 捕获错误
  }
}

Promise的基本实现的构思已经全部写完啦!