Promise系列3——Promise 实现

121 阅读3分钟

Promise 实现

前两节花费了很大的劲总结一下promise 的使用场景,基本用法以及promise A+ 规范解读,通过规范实现以下promise,从代码层面反向在理解一下规范的定义

如何使用

先定义一下如何使用 promise

const promise = new Promise((resolve,reject)=>{
	resolve("x")
})

promise.then(res=>{
	console.log("结果:", res); // 结果:x
})

开始编码

核心逻辑

  • Promise是一个类,使用new Promise 返回一个promise对象, 接受一个executor执行器函数, 并且在实例化的时候立即调用执行。
  • executor 接收两个参数resolvereject, 同时这两个参数也是函数。
  • Promise 实例具有三种状态, pending,fulFilled, rejected,并且状态改变是单向的,一经改变, 将不能再修改。
  • promise 实例 都有 then方法。then 方法中有两个参数。onResolved成功回调函数, onRejected失败回调函数
  • 执行器executor调用resolve后, then中onResolved将会执行, 当执行器executor调用reject后, then方法第二个参数onRejected将会执行。

框架如下

  1. 构造函数, new Promise() 会接受一个函数,函数里面有两个参数,分别表示成功和拒绝的回调,此时的状态是 pending
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 拒绝

class PromiseCustom {
  // 接受一个处理函数,先完成成功的回调
	constructor(executor) {
    this.state = PENDING; // 进入状态是 pending
    
    executor(this.triggerResolve.bind(this))
  }
  // 成功的回调函数
  triggerResolve(val) {
  	// TODO 
  }
}
  1. then 方法可以注册多个,也就是成功回调和拒绝回调函数是多个,然后依次调用
constructor(executor) {
  // 初始化一个数组,把成功回调push数组中
	this.fulfilledList = []
}

triggerResolve(val) {
  setTimeout(()=>{
    // 判断状态
    if(this.state!==PENDING) return
  	// 改变状态
    this.state = FULFILLED;
    // 处理回调
    this.fulfilledList.forEach(item => item(val))
    // 清空数组
    this.fulfilledList = []
  },0)
}

// 在then方法里面需要把成功的回调push到数组

  1. then 方法,接受两个参数,onResolved成功回调函数, onRejected失败回调函数。
// 成功的回调函数,该函数是在实例化是注册,在.then 方法使用,所以通过setTimeout处理
triggerResolve(val) {
  setTimeout(()=>{
    // 判断状态
    if(this.state!==PENDING) return
  	// 改变状态
    this.state = FULFILLED;
    // 处理回调
  },0)
}
// then 方法可以注册多个,所以需要一个递归调用
then(onFulfilled, onRejected) {
	const {state} = this
  // 实例化下一个promise
 	const promiseInstance = new PromiseCustom((onNextFulfilled, onNextRejected) => {
    // 处理回调  
    function onFinalFulfilled(val) {
      // 判断当前成功回调是否是一个函数,如果不是则忽略(规范2.2)
      // 执行下一个then
      if (typeof onFulfilled !== 'function') {
        onNextFulfilled(val)
      } else {
        const res = onFulfilled(val)
        // 判断是否有.then 方法:
        // 如果有使用结果的then方法(规范2.3)
        // 如果没有把结果当做下一个then的值
        if (res && typeof res.then === 'function') {
          res.then(onNextFulfilled)
        } else {
          onNextFulfilled(res)
        }
      }
    }
    // 添加成功回调
    if (state===PENDING) this.fulfilledList.push(onFinalFulfilled)
  })
	// 返回当前实例
  return promiseInstance
}

完整代码

const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 拒绝

class PromiseCustom {
  constructor(executor) {
    this.state = PENDING;// 进入状态是 pending
    this.fulfilledList = []

    executor(this.triggerResolve.bind(this))
  }

  triggerResolve(val) {
    setTimeout(() => {
      if (this.state !== PENDING) return
      this.state = FULFILLED
      this.fulfilledList.forEach(item => item(val))
      this.fulfilledList = []
    }, 0)
  }

  then(onFulfilled, onRejected) {
    const { state } = this
    const promiseInstance = new PromiseCustom((onNextFulfilled, onNextRejected) => {
      function onFinalFulfilled(val) {
        if (typeof onFulfilled !== 'function') {
          onNextFulfilled(val)
        } else {
          const res = onFulfilled(val)
          if (res && typeof res.then === 'function') {
            res.then(onNextFulfilled)
          } else {
            onNextFulfilled(res)
          }
        }
      }
      if (state===PENDING) this.fulfilledList.push(onFinalFulfilled)
    })
    return promiseInstance
  }
}

使用自定义的Promise

const promise = new PromiseCustom((resolve, reject) => {
  setTimeout(() => {
    resolve("XXX")
  }, 1000)
})

promise.then(res => {
  console.log("结果:", res)
  return "X"
}).then(res => {
  console.log(res)
})
// 结果: XXX
// X

扩展

添加拒绝状态处理函数

// 1. 添加错误回调数组,并在实例化时候注册拒绝处理函数
constructor(){
	this.rejectedList = [];
}
// 2. 添加错误处理函数
triggerReject(val) {
  setTimeout(() => {
    if (this.state !== PENDING) return;
    this.state = REJECTED;
    this.rejectedList.forEach(item => item(val))
    this.rejectedList = []
  }, 0)
}

// 添加处理过程,onFinalFulfilled

function onFinalRejected(val) {
  if (typeof onRejected !== 'function') {
    onNextRejected(val)
  } else {
    const res = onRejected(val)
    // 只处理 reject 时 return 情况,没有考虑到 throw Error
    if (res && typeof res.then === 'function') {
      res.then(onNextFulfilled, onNextRejected)
    } else {
      onNextFulfilled(res)
    }
  }
}

if (state===PENDING) {
  // ... 
  this.rejectedList.push(onFinalRejected)
}

添加静态方法

  1. resole & reject
static resole(val) {
  return new CustomPromise((resolve, reject) => {
    resolve(val)
  })
}

static reject(val) {
  return new CustomPromise((resolve, reject) => {
    reject(val)
  })
}
  1. all
static all(list) {
  return new CustomPromise((resolve, reject) => {
    let count = 0;
    const values = []
    for (const [i, customPromiseInstance] of list.entries()) {
      customPromiseInstance
        .then(
        res => {
          values[i] = res;
          count++;
          if (count === list.length) resolve(values)
        },
        err => {
          reject(err)
        }
      )
    }
  })
}

Catch 方法

catch(onRejected) {
  return this.then(null, onRejected)
}