手写Promise原理,你一定可以看懂

1,008 阅读4分钟

一、什么是Promise?

Promise是异步微任务,解决了传统回调函数的嵌套问题。简化了代码的书写,解决了异步多层嵌套回调的问题,让代码的可读性更高。Promise我们都会用,那它的原理是什么呢?

二、分析Promise

1. Promise是ES6新增的一个构造函数,可以用new Promise() 出一个实例对象。这个构造函数接收一个函数作为参数,这个函数有两个参数,分别是两个函数 resolvereject。而这个实例对象又可以使用.then和.catch两个方法。返回出来的还是一个Promise对象,所以Promise可以链式调用。

所以我们可以写出大体的一个框架:

  1. 定义几个公共的状态变量
  2. 定义几个变量以便后面使用
  3. 构造函数内定义resolvereject两个函数
  4. 构造函数外部有thencatch两个函数
//定义公共状态变量
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'

class MyPromise{
  constructor(fn){
    this.state = PENDING          //起始状态
    this.value = null            //用来存放resolve() 内部的参数
    this.resloveCallBacks = []  //存放.then() 里面的回调函数
    this.rejectCallBacks = []  //存放 .catch() 里面的回调函数

    let resolve = value =>{}
    let reject = value =>{}

    try {
      fn(resolve,reject)      
    } catch (error) { 
      reject(error)
    }
  }
  
  then(onFufilled,onRejected){}
  catch(onFufilled,onRejected){}
}

2. 大体框架写好之后我们再次分析

  • Promise的状态一经变更之后,是不可逆转的。所以我们要在resolvereject两个函数判断。只有为pending状态时才执行。
  • Promise的resolvereject一经调用,马上会执行.then()里面的函数。 代码变更为:
    let resolve = value =>{
      if(this.state === PENDING){
        this.state = RESOLVED
        this.value = value
        this.resloveCallBacks.map(cb =>cb(this.value)) //立即执行.then()里面的回调函数
      }
    }
    let reject = value =>{
      if(this.state === PENDING){
        this.state = REJECTED
        this.value = value
        this.rejectCallBacks.map(cb => cb(this.value))
      }
    }

3. 然后再对then分析

  • then 可以接收两个回调函数,一个成功,一个失败。
  • then 里面的回调函数的值就是resolve或reject出来的值。
  • then 里面的参数一定要是函数 所以代码变更为:
  then(onFufilled,onRejected){
    //先判断参数的类型
    if(typeof onFufilled === 'function' ? onFufilled : v => v)
    if(typeof onRejected === 'function' ? onRejected : r =>{
      throw r
    })
    
      if(this.state == PENDING){ //如果还是pending状态,不执行后面的函数
      this.ResolvedFunctions.push(onFufilled) //将函数存入相对应的数组
      this.RejectedFunctions.push(onRejected)
    }
      if(this.state == RESOLVED){  //已经调用
        onFufilled(this.value)     //立即执行回调函数
      }
      if(this.state == REJECTED){
        onRejected(this.value)
      }
}

完整代码:

const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'

class MyPromise{
  constructor(fn){
    this.state = PENDING  //保存状态
    this.value = null     // 保存resolve() 和 reject() 的参数
    this.ResolvedFunctions = []  //保存then 里面的第一个函数
    this.RejectedFunctions = []  //保存then 里面的第二个函数

    let resolve = value =>{
      if(this.state === PENDING){
        this.state = RESOLVED
        this.value = value
        this.ResolvedFunctions.map( cb => cb(this.value))
      }
    }
    
    let reject = value =>{
      if(this.state === PENDING){
        this.state = REJECTED
        this.value = value
        this.RejectedFunctions.map( cb => cb(this.value))
      }
    }

    try {
      fn(resolve,reject)
    } catch (error) {
      reject(error)
    }
  }

  then( onFufilled,onRejected){
    //判断参数是否为函数类型 
    if(typeof onFufilled === 'function' ? onFufilled : v => v)
    if(typeof onRejected === 'function' ? onRejected : r => {r
      throw r
    })
    if(this.state == PENDING){
      this.ResolvedFunctions.push(onFufilled)
      this.RejectedFunctions.push(onRejected)
    }
      if(this.state == RESOLVED){
        onFufilled(this.value)
      }
      if(this.state == REJECTED){
        onRejected(this.value)
      }

  }
}

这样一个最丐版的Promise就写好了,我们来测试一下:

const p =new MyPromise((resolve,reject) =>{
 setTimeout(() =>{
    resolve('yes')
 },1000)
 })
 p.then(
   res =>{
   console.log(res);
 })

测试结果:我们可以看到在过了一秒,reslove执行完之后,才会执行.then()

promise.gif

4.链式调用

then会有几个特点:

  • 1、then方法本身会返回一个新的Promise对象
  • 2、如果返回值是promise对象,返回值为成功,新promise就是成功
  • 3、如果返回值是promise对象,返回值为失败,新promise就是失败
  • 4、如果返回值非promise对象,新promise对象就是成功,值为此返回值 那么如何链式调用呢,将then再次封装成一个Promise对象返回

具体代码如下:

  then(onFufilled,onRejected){
    if(typeof onFufilled === 'function' ? onFufilled : v => v)
    if(typeof onRejected === 'function' ? onRejected : r =>{
      throw r
    })

    //返回一个Promise对象
    var thenPromise = new MyPromise((resolve,reject) =>{

      const resolvePromise = cb =>{
        try {
          const x = cb(this.value)
          if(x === thenPromise){
            throw new Error('不能返回自身')
          }
          //如果还是Promise对象,则继续调用then方法
          if(x instanceof MyPromise){
            x.then(resolve,reject)
          }else{
          //否则直接成功
            resolve(x)
          }
        } catch (error) {
            reject(error)
            throw new Error(error)
        }
      }
      if(this.state === PENDING){
      // 如果状态为待定状态,暂时保存两个回调
        this.resloveCallBacks.push(resolvePromise.bind(this,onFufilled))
        this.rejectCallBacks.push(resolvePromise.bind(this,onRejected))
      }
      if(this.state === RESOLVED){
      // 如果当前为成功状态,执行第一个回调
        resolvePromise(onFufilled)
      }
      if(this.state === REJECTED){
      // 如果当前为失败状态,执行第二个回调
        resolvePromise(onRejected)
      }
    })
    
    return thenPromise
  }

我们测试用例:

  const p = new MyPromise((resolve,reject) =>{
    resolve(2)
  }).then(res =>2 * res)
  .then(res =>{
    console.log(res);
  })

用例结果:输出了第二个then的执行结果

image.png

这就是Promise的手写过程,希望能对你理解Promise有一定的帮助。