手写Promise

219 阅读23分钟

一、Promise 核心逻辑的实现

在实现其原理之前,必须要对promise有足够多的了解。

分析一波:

  • Promise是一个类,在new一个promise实例的时候需要传递一个执行器(函数)进行,执行器会立即执行。
  • Promise有两个实例的方法 resolve 方法和 reject 方法,这两个方法会在执行器函数执行的时候作为参数传入,用于改变Promise的状态。
  • Promise有三种状态,分别为:成功状态 -> fulfilled ,失败状态 -> rejected, 等待状态 -> pending。Promise默认状态为等待状态,状态的更改通过resolve方法和reject方法,resolve方法用于将状态从pending更改为fulfilled,reject方法用于将状态从pending状态更改为rejected。一旦状态更改就不能再更改了。
  • Promise还有一个原型上的then方法,该方法接受两个回调函数,一个是成功状态(fulfilled)的回调函数,一个是失败状态(rejected)的回调函数。两个回调函数分别接受resolve和reject传递的value值。
  • then方法还可以进行链式调用,这表明then方法中返回了一个promise对象,后面的then方法可以拿到前面一个then方法的返回值。

1. promise处理同步代码

// 根据上面的分析,我们可以得到如下代码

// 2. 定义Promise三种状态
const FULFILLED = 'fulfilled'
const PENDING = 'pending'
const REJECTED = 'rejected'

class MyPromise {
  // 1. 执行器会立即执行,接受两个实例方法
  constructor(executor) {
    executor(this.resolve, this.reject)
  }
  // 实例属性定义
  // promise状态默认为 等待状态
  status = PENDING
  // 成功状态的值
  value = null
  // 失败状态的值
  reason = null
  
  // 必须要用箭头函数,来将其this与实例进行绑定
  resolve = (value) => {
    // 3. resolve方法将promise状态便成为成功的状态,状态变更之后就不能够再次更改.
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value
  }

  reject = (reason) => {
    // 4. reject方法将promise状态便成为失败的状态,状态变更之后就不能够再次更改.
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason
  }

  // 定义原型then方法
  then(successCallback, faildCallback) {
    // 5. 判断promise的状态,如果是成功的状态调用成功的回调函数,如果是失败的状态调用失败的回调函数
    if (this.status === FULFILLED) {
      // 回调函数的值,需要在调用resolve方法的时候进行保存
      successCallback(this.value)
    } else if (this.status === REJECTED) {
      // 回调函数的值,需要在调用rejected方法的时候进行保存
      faildCallback(this.reason)
    }
  }
}

// 测试一波
const promise = new MyPromise((resolve, reject) => {
  // resolve('hello reborn jiang')
  // reject('hello reborn jiang')
  setTimeout(() => {
    resolve('hello reborn jiang')
  }, 0);
})

promise.then(value => {
  console.log(value, '成功状态的值') // hello reborn jiang 成功状态的值
}, reason => {
  console.log(reason, '失败状态的值') // hello reborn jiang 失败状态的值
})

为什么当执行器(executor)函数中有异步代码的时候会导致没有任何打印消息? 解释: 当执行器函数里面拥有异步代码的时候,此时调用then方法的时候回调函数就不再执行。导致在执行then方法的时候此时还没有调用过resolve方法与reject方法去更改promise的状态,所以状态还依旧是pending状态,可是then方法中还没有对pending状态进行处理。所以就没有打印结果。

从以上分析中可以得到一点结论: then方法中如果此时时pending状态,执行器中的代码一定时异步的任务

上面解释涉及到js执行机制,简单来说 这是因为执行器里面的是异步代码,异步任务会交给浏览器的的线程来处理,等待异步任务完成时将其加入消息队列中,等待调用栈代码执行完之后EventLoop会从消息队列取任务执行。 如果对JS执行机制还不是很了解的朋友们,可以看笔者的另外一篇关于JS执行机制的文章哈~

2. promise 处理异步代码

分析一波:

  • then方法中如果此时还是pending状态,证明执行器中的代码一定时异步的任务。
  • 如果在pending状态下直接调用then方法的两个回调函数的话是拿不到resolve或是reject传递的值的。
  • 所以我们将在pending状态的时候将回调函数存储起来,等到resolve方法或是reject方法执行的时候在调用then方法的成功或是失败的回调。
// 基于以上分析我们可以得到如下代码

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

class MyPromise {
  constructor(executor) {
    executor(this.resolve, this.reject)
  }
  status = PENDING
  value = null
  reason = null

  // 2. 定义两个变量存储成功或是失败的回调
  successCallback = null
  faildCallback = null

  resolve = (value) => {
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value
    // 3. 在resolve方法执行时再次调用。
    this.successCallback && this.successCallback(value)
  }
  reject = (reason) => {
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason
    
    // 3. 在resolve方法执行时再次调用
    this.faildCallback && this.faildCallback(reason)
  }
  then(successCallback, faildCallback) {
    if (this.status === FULFILLED) {
      successCallback(this.value)
    } else if (this.status === REJECTED) {
      faildCallback(this.reason)
    } else {
      // pengding 证明executor有异步任务
      // 1. 存储回调函数,待resolve,reject执行时再次调用
      console.log('哦时异步任务,pending中的代码执行了')
      this.successCallback = successCallback
      this.faildCallback = faildCallback
    }
  }
}

// 测试一波
const promise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('hello reborn jiang')
  }, 0);
})

promise.then(value => {
  console.log(value, '成功状态的值') 
}, reason => {
  console.log(reason, '失败状态的值') 
})

// 打印结果如下:
// 哦时异步任务,pending中的代码执行了
// hello reborn jiang 成功状态的值

总结: 哈哈哈,你真棒~ 到这里你已经实现了一个简版的promise可以用来处理同步和异步任务了,接下来挑战难度升级,我们将实现then方法的相关功能与一些细节。

二、then方法功能进一步的实现

1. promise实例的then方法可以多次调用

promise实例的then方法在处理异步任务可以多次调用,其所调用的每个then方法中的回调函数都会执行。

Promise(示例):

// 
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('hello reborn jiang')
  },0)
})
promise.then(res => {
  console.log(res, '第一次调用')
})
promise.then(res => {
  console.log(res, '第二次调用')
})
promise.then(res => {
  console.log(res, '第三次调用')
})
// console结果如下:
// hello reborn jiang 第一次调用
// hello reborn jiang 第二次调用
// hello reborn jiang 第三次调用

MyPromise(示例):

const promise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('hello world')
  }, 0);
})

promise.then((value) => {
  console.log(value, '成功状态的值1')
})
promise.then((value) => {
  console.log(value, '成功状态的值2')
})

promise.then((value) => {
  console.log(value, '成功状态的值3')
})
// 打印如下:
// 哦时异步任务,pending中的代码执行了
// 哦时异步任务,pending中的代码执行了
// 哦时异步任务,pending中的代码执行了
// hello world 成功状态的值3

结论如下: 出现这种情况的原因是因为在处理异步任务的时候,then方法会先执行,在then方法的pending条件中存储回调的方法仅仅只是一个变量,这也就导致不能够都所有=的回调函数保存,因此最后一个执行的then会覆盖前面的回调函数。

MyPromise(修改版):

// 基于以上分析我们可以得到如下代码

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

class MyPromise {
  constructor(executor) {
    executor(this.resolve, this.reject)
  }
  status = PENDING
  value = null
  reason = null
  // successCallback = null
  // faildCallback = null
  // 1. 存储回调函数的变量需要是一个Array,确保每个回调都能够存储。
  successCallbackList = []
  faildCallbackList = []

  resolve = (value) => {
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value
    // this.successCallback && this.successCallback(value)
    // 3. 等待异步任务回调执行的时候,开始循环遍历then回调函数执行。
    while (this.successCallbackList.length)this.successCallbackList.shift()(value)

  }
  reject = (reason) => {
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason
    // this.faildCallback && this.faildCallback(reason)
    // 3. 等待异步任务回调执行的时候,开始循环遍历then回调函数执行。
    while (this.faildCallbackList.length) this.faildCallbackList.shift()(reason)
  }
  then(successCallback, faildCallback) {
    if (this.status === FULFILLED) {
      successCallback(this.value)
    } else if (this.status === REJECTED) {
      faildCallback(this.reason)
    } else {
      // this.successCallback = successCallback
      // this.faildCallback = faildCallback
      // 2. 将每次调用的回调函数存储到数组中
      successCallback instanceof Function &&
        this.successCallbackList.push(successCallback)
      faildCallback instanceof Function &&
        this.faildCallbackList.push(faildCallback)
    }
  }
}

// 测试一波
const promise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('hello reborn jiang')
  }, 0)
})

promise.then((value) => {
  console.log(value, '成功状态的值1')
})
promise.then((value) => {
  console.log(value, '成功状态的值2')
})
promise.then((value) => {
  console.log(value, '成功状态的值3')
})
// 打印结果
// hello reborn jiang 成功状态的值1
// hello reborn jiang 成功状态的值2
// hello reborn jiang 成功状态的值3

2. then 方法的链式调用

分析一波:

  • then方法可以进行链式调用,证明其内部有返回新的promise对象
  • then方法回调函数返回值分为两种情况,一种是返回普通值,直接调用新创建的promise对象的resolve将值给保存在这个新创建的实例上。如果是then方法返回的是promise对象,我们需要了解到这个promise的状态是成功的还是失败的,如果是成功的调用resolve方法,如果是失败的调用reject方法。(补充说明普通值的情况)
    • 普通值:前面一个then方法的回调函数(无论成功回调或是失败回调)的返回值会作为后面一个then方法的成功回调的参数

Promise代码如下(示例)

// 前面两点总结示例代码
const promise = new Promise((resolve, reject) => {
  resolve('hello reborn')
})
promise.then(value => {
  console.log(value, '第一个then')
  return 'hello David'
}).then(value => {
  console.log(value, '第二个then')
}, )
// 打印如下
// hello reborn 第一个then
// hello David 第二个then

// 第二点的解释 失败回调的案例
const promise = new Promise((resolve, reject) => {
  reject('hello reborn')
})

promise.then(() => {}, 
reason => {
  console.log(reason, '失败回调')
  return 'errorr'
}).then(value => {
  console.log(value, '成功回调')
}, reason => {
  console.log(reason, '失败回到')
})
// 打印如下
// hello reborn 失败回调
// errorr 成功回调

// then回调返回promise对象的情况
const promise = new Promise((resolve, reject) => {
  resolve('hello reborn')
})

promise.then(value => {
  console.log(value, '第一个then执行')
  return new Promise((resolve, reject) => {
    resolve('success to SecondThen')
  })
}).then(value => {
  console.log(value, '第二个then方法执行')
})
// 打印结果
// hello reborn 第一个then执行
// success to SecondThen 第二个then方法执行

MyPromise代码:

// 基于以上分析我们可以得到如下代码

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

class MyPromise {
  constructor(executor) {
    executor(this.resolve, this.reject)
  }
  status = PENDING
  value = null
  reason = null
  successCallbackList = []
  faildCallbackList = []

  resolve = (value) => {
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value
    while (this.successCallbackList.length)
      this.successCallbackList.shift()(value)
  }
  reject = (reason) => {
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason
    while (this.faildCallbackList.length) this.faildCallbackList.shift()(reason)
  }
  then(successCallback, faildCallback) {
    // 1. 支持链式调用,肯定需要返回一个新的promise(不能够返回this,是因为旧的promise可能包含了状态值,回调函数list等等)
    const promise2 = new MyPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        // 2. 需要判断当前promise对象返回的是普通值还是promise对象
        // 普通值直接调用resolve方法将值传递给到下一个then方法
        // 如果是then方法返回的是promise对象,需要判断当前返回的promise对象的状态
        // 如果是成功的状态,调用promise2的resolve方法将then返回的promise对象的值传递给到下一个then
        // 如果是失败的状态,调用promise2的reject的方法将then返回的promise对象的失败值传到下一个then的第二个参数
        const successCallBackValue = successCallback(this.value)
        // 3. 不仅要在FULFILLED情况下要判断,REJECTED, PENDING都要判断,封装一个方法
        resolvePromise(successCallBackValue, resolve, reject)
      } else if (this.status === REJECTED) {
        const faildCallbackReason = faildCallback(this.reason)
      } else {
        successCallback instanceof Function &&
          this.successCallbackList.push(successCallback)
        faildCallback instanceof Function &&
          this.faildCallbackList.push(faildCallback)
      }
    })
    return promise2
  }
}

function resolvePromise(returnVal, resolve, reject) {
  // 4. 判断状态
  if (returnVal instanceof MyPromise) {
    // 6. promise对象, 查看状态之后,调用resolve 或是 reject
    // returnVal.then(value => resolve(value), reason => reject(reason))
    // 可以简写如下
    returnVal.then(resolve, reject)
  } else {
    // 5. 是普通值,调用resolve方法将当前then的返回值传递给到下一个then
    resolve(returnVal)
  }
}

// 测试一波
const promise = new MyPromise((resolve, reject) => {
  resolve('hello reborn jiang')
})

// 普通值
promise
  .then((value) => {
    console.log(value, '第一个then')
    return 'hello world'
  }).then(value => {
    console.log(value, '第二个then')
  })
// 输出结果如下
// hello reborn jiang 第一个then
// hello reborn jiang 第二个then


// promise对象
promise.then(value => {
  console.log(value, '第一个then')
  return new MyPromise((resolve, reject) => {
    resolve('success to secondThen')
  })
}).then(value => {
  console.log(value, '第二个then')
})
// 输入如下:
// hello reborn jiang 第一个then
// success to secondThen 第二个then

// 测试第一个then返回的是带有失败状态的promise
promise.then(value => {
  console.log(value, '第一个then')
  return new MyPromise((resolve, reject) => {
    reject('faild to secondThen')
  })
}).then(value => {
  console.log(value, '第二个then成功')
}, reason => {
  console.log(reason, '第二个then 失败')
})

// 打印结果如下:
// hello reborn jiang 第一个then
// faild to secondThen 第二个then 失败

恭喜你,你已经实现了大部分then方法的功能,还剩下一些小细节待完善,继续加油鸭~

后面的内容会在今天完成,请持续关注哦~

3. then方法的链式调用识别 Promise 对象自返回

解释一下标题的意思: 在then方法的链式调用中,如果当前then方法返回的promise对象又作为当前then方法回调函数的返回值这会发生什么问题,大家可以先思考一下?再继续往下阅读~

Promise代码如下(示例)

// promise then返回当前对象

const promise = new Promise((resolve, reject) => {
  resolve('hello morning')
})
const promise1 = promise.then(res => {
  return promise1
})
// 打印如下: 
// TypeError: Chaining cycle detected for promise #<Promise>
// 抛出类型错误,检测到 promise 链式循环

用我们之前的代码演示 then方法的链式调用时 Promise 对象自返回,会带来什么样的问题?

MyPromise 代码如下(示例)

要在then回调中拿到当前then返回的promise对象有两种方法 第一种方法


const promise = new MyPromise((resolve, reject) => {
  resolve('hello reborn')
})
// 1. 此时我们的 MyPromise 还不能够想 Promise 一样, 在then方法里直接拿到 当前then方法返回的promise对象,这是因为 then方法里还没有做任何处理。
// const promise1 = promise.then(value => {
//   return promise1
// })

// 2. 不过没关系,我们可以借助定时器,等then方法内执行回调函数时发现又定时器,就会继续往下执行,先返回then方法的promise1对象之后回来再执行回调函数里面的内容,此时回调中就能够拿得到promise1了
const promise1 = promise.then(value => {
  setTimeout(() => {
    return promise1
  }, 0);
}).then(res => {
  console.log(res, 'promise1') // undefined promise1的返回值
})
// 3. 第二个then 方法并不能够拿得到前面一个then返回的promise对象,拿到的时undefined。

分析 在这里插入图片描述 第二种方法

then(sucessCallback, faildCallback) {
    const promise2 = new MyPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        // 1. 利用定时器延期执行回调函数。原理与文章第一种方法相同
        setTimeout(() => {
          const sucessCallBackValue = sucessCallback(this.value)
          resolvePromise(sucessCallBackValue, resolve, reject)
        }, 0);
      } else if (this.status === REJECTED) {
        const faildCallbackReason = faildCallback(this.reason)
      } else {
     	 console.log('是否执行了两次')
        sucessCallback instanceof Function &&
          this.sucessCallbackList.push(sucessCallback)
        faildCallback instanceof Function &&
          this.faildCallbackList.push(faildCallback)
      }
    })
    return promise2
  }

const promise = new MyPromise((resolve, reject) => {
  resolve('hello reborn')
})
const promise1 = promise.then(value => {
  return promise1
}).then(res => {
  console.log(res, 'promise1')
})
// 打印结果
// 是否执行了两次
// MyPromise {
//   status: 'pending',
//   value: null,
//   reason: null,
//   sucessCallbackList: [],
//   faildCallbackList: [],
//   resolve: [Function: resolve],
//   reject: [Function: reject]
// } returnVal
// 是否执行了两次

代码执行结果分析如下: 在这里插入图片描述 结论

如果不对 当前then方法返回的promise对象又作为当前then方法的回调的返回值这种情况做处理,会导致调用链执行 ”断层“ 的这种情况,即除了第一个确定状态的promise的then方法的回调能够执行,其他then方法返回的promise对象都处于pending状态,然后其回调函数都会被推到successCallBackList或是faildCallBackList中等待当前promise(也就是第一个then方法)中的resolve方法或是reject方法执行之后下一个then方法的才会执行其回调函数。问题是第一个then方法的回调中,将本来用于调用第二个then方法回调的resolve和reject方法push到successCallBackList或faildCallBackList中,导致后面的then方法的回调都没有办法执行,在第一个then回调执行直接也没有能够调用resolve或是reject,自然后面一个then回调不能够执行,因为后面一个then回到不能够执行,它里面的resolve reject也不能够调用,第三个也不能执行........后面的所有then回调都不能执行。

看下面的图更容易理解

在这里插入图片描述

避免自调用的问题很简单,请查看下面代码

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

class MyPromise {
  constructor(executor) {
    executor(this.resolve, this.reject)
  }
  status = PENDING
  value = null
  reason = null
  successCallbackList = []
  faildCallbackList = []

  resolve = (value) => {
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value
    while (this.successCallbackList.length)
      this.successCallbackList.shift()(value)
  }
  reject = (reason) => {
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason
    while (this.faildCallbackList.length) this.faildCallbackList.shift()(reason)
  }
  then(successCallback, faildCallback) {
    const promise2 = new MyPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        setTimeout(() => {
          const successCallBackValue = successCallback(this.value)
          // 1. 将 then方法中返回的promise2传入给到resolvePromise方法中 去跟 then回调返回的值做判断。
          resolvePromise(promise2, successCallBackValue, resolve, reject)
        }, 0);
      } else if (this.status === REJECTED) {
        const faildCallbackReason = faildCallback(this.reason)
      } else {

        successCallback instanceof Function &&
          this.successCallbackList.push(successCallback)
        faildCallback instanceof Function &&
          this.faildCallbackList.push(faildCallback)
      }
    })
    return promise2
  }
}
function resolvePromise(selfPromise, returnVal, resolve, reject) {
  // 2. 如果相等之后抛出异常并阻止代码向下执行
  if (returnVal === selfPromise) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  if (returnVal instanceof MyPromise) {
    returnVal.then(resolve, reject)
  } else {
    resolve(returnVal)
  }
}
const promise = new MyPromise((resolve, reject) => {
  resolve('hello reborn')
})

const promise1 = promise.then(res => {
  console.log(res)
  return promise1
})
promise1.then(() => {}, reason => {
  console.log(reason.message)
})

// 打印结果如下:
// hello reborn
// Chaining cycle detected for promise #<Promise>

4. then方法捕获异常处理,完善其他功能

任何一个工具库或是框架都会进行异常处理,来保持代码的"健壮性,现在来完善MyPromise" 分析:

  • 我们首先要先确保自己的代码不会报错,那么错误的来源只有可能是外部输入性的错误,也只有外部回调函数会参与我们的代码执行
    • executor执行函数
    • then方法的回调函数调用
const FULFILLED = 'fulfilled'
const PENDING = 'pending'
const REJECTED = 'rejected'

class MyPromise {
  constructor(executor) {
    // 1. 利用try catch 来捕获代码错误
    try {
      executor(this.resolve, this.reject)
    } catch (err) {
      this.reject(err)
    }
  }
  status = PENDING
  value = null
  reason = null
  successCallbackList = []
  faildCallbackList = []

  resolve = (value) => {
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value
    while (this.successCallbackList.length)
      this.successCallbackList.shift()(value)
  }
  reject = (reason) => {
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason
    while (this.faildCallbackList.length) this.faildCallbackList.shift()(reason)
  }
  then(successCallback, faildCallback) {
    const promise2 = new MyPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        setTimeout(() => {
          try {
            const successCallBackValue = successCallback(this.value)
            resolvePromise(promise2, successCallBackValue, resolve, reject)

          } catch (err) {
            reject(err)
          }
        }, 0);
      } else if (this.status === REJECTED) {
        const faildCallbackReason = faildCallback(this.reason)
      } else {
        successCallback instanceof Function &&
          this.successCallbackList.push(successCallback)
        faildCallback instanceof Function &&
          this.faildCallbackList.push(faildCallback)
      }
    })
    return promise2
  }
}
function resolvePromise(selfPromise, returnVal, resolve, reject) {
  if (returnVal === selfPromise) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  if (returnVal instanceof MyPromise) {
    returnVal.then(resolve, reject)
  } else {
    resolve(returnVal)
  }
}
const promise = new MyPromise((resolve, reject) => {
  resolve('hello reborn')
  // 2. 打印一个未定义的a
  // console.log(a)
})

// 3. 测试一波

promise.then(res => {

}, reason => {
  // executor错误
  console.log(reason.message, '打印错误')
})
// 打印结果
// a is not defined 打印错误


// 回调错误
promise.then(res => {
  // 4. 在then方法创建一个回调的错误,在下一个then的失败的回调函数需要进行捕获到
  // throw new Error("")
  console.log(b)
}).then(res => { }, reason => {
  console.log(reason.message, '捕获then方法的错误')
})
// 打印结果
// b is not defined 捕获then方法的错误

此时我们在then方法也只对状态为FULFILLED情况处理成功,REJECTED和PENDING都没有进行处理,请看下面对REJECTED与PENDING代码做的处理

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

class MyPromise {
  constructor(executor) {
    try {
      executor(this.resolve, this.reject)
    } catch (err) {
      this.reject(err)
    }
  }
  status = PENDING
  value = null
  reason = null
  successCallbackList = []
  faildCallbackList = []

  resolve = (value) => {
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value
    while (this.successCallbackList.length)
      this.successCallbackList.shift()()
  }
  reject = (reason) => {
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason
    while (this.faildCallbackList.length) this.faildCallbackList.shift()()
  }
  then(successCallback, faildCallback) {
    const promise2 = new MyPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        setTimeout(() => {
          try {
            const successCallBackValue = successCallback(this.value)
            resolvePromise(promise2, successCallBackValue, resolve, reject)

          } catch (err) {
            reject(err)
          }
        }, 0);
      } else if (this.status === REJECTED) {
        // 1. 对失败状态的处理与成功是一样的
        // - 对失败的的回调函数做异常处理
        // - 将失败函数的普通返回值作为下一个then方法成功函数的返回值
        // - 如果返回的是promise对象,调用当前promise对象的then方法取得返回值,通过resolve或是reject方法传递给到下一个then回调中
        // - promise对象自调用需要抛出异常
        setTimeout(() => {
          try {
            const faildCallbackReason = faildCallback(this.reason)
            resolvePromise(promise2, faildCallbackReason, resolve, reject)
          } catch (err) {
            reject(err)
          }
        }, 0);

      } else {
        // 2. 对pending状态的代码做处理
        // - 对then方法的回调函数做异常处理,此时我们需要外部再用一个函数进行包裹,里面调用成功回调才能写try catch
        // - 剩下与 FULFILLED && REJECTED 状态时的处理一样的

        successCallback instanceof Function &&
          this.successCallbackList.push(() => {
          // 感觉这个定时器可有可无,then方法会先执行返回promise对象,回调函数会在thne方法之后执行,这里肯定是可以拿得到then方法返回的promise对象的
            setTimeout(() => {
              try {
                const successCallBackValue = successCallback(this.value)
                resolvePromise(promise2, successCallBackValue, resolve, reject)

              } catch (err) {
                reject(err)
              }
            }, 0);
          })
        faildCallback instanceof Function &&
          this.faildCallbackList.push(() => {
            setTimeout(() => {
              try {
                const faildCallbackReason = faildCallback(this.reason)
                resolvePromise(promise2, faildCallbackReason, resolve, reject)
              } catch (err) {
                reject(err)
              }
            }, 0);
          })
      }
    })
    return promise2
  }
}
function resolvePromise(selfPromise, returnVal, resolve, reject) {
  if (returnVal === selfPromise) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  if (returnVal instanceof MyPromise) {
    returnVal.then(resolve, reject)
  } else {
    resolve(returnVal)
  }
}
const promise = new MyPromise((resolve, reject) => {
  reject('no reborn')
})

// 3. 测试then方法对失败函数的处理

promise.then(res => {

}, reason => {
  console.log(reason)
  return '传递给到下一个then'
}).then(res => {
  console.log(res)
})
// 打印结果:
// no reborn
// 传递给到下一个then

// 4. 测试pending状态下的处理
promise.then(res => {
  console.log(res)
  return 'hello Boom'
}).then(res => {
  console.log(res)
})

// 打印结果
// hello reborn
// hello Boom

5. 将then变为可选参数

then方法可以不传递回调作为参数,会将promise的状态一直向下传递,直到then方法有回调函数的时候接受传递的参数

Promise演示

const promise = new Promise((resolve, reject) => {
  resolve('hhhhh')
})
promise.then().then().then().then(res => {
  console.log(res)
})
// 打印结果
// hhhhh

分析:

  • 判断then方法有没有回调函数,如果没有回调函数的话,我们就补一个回调函数 value => value,这样就会将状态进行传递下去。
const FULFILLED = 'fulfilled'
const PENDING = 'pending'
const REJECTED = 'rejected'

class MyPromise {
  constructor(executor) {
    try {
      executor(this.resolve, this.reject)
    } catch (err) {
      this.reject(err)
    }
  }
  status = PENDING
  value = null
  reason = null
  successCallbackList = []
  faildCallbackList = []

  resolve = (value) => {
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value
    while (this.successCallbackList.length)
      this.successCallbackList.shift()()
  }
  reject = (reason) => {
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason
    while (this.faildCallbackList.length) this.faildCallbackList.shift()()
  }
  then(successCallback, faildCallback) {
    // 1. value => value 可以将上一个promise对象的值 给到当前then返回的promise对象,下个then就可以接受到
    successCallback = successCallback instanceof Function ? successCallback : value => value
    // 2. 如果时失败的状态的promise可以利用 reason => { throw reason} ,这样回调函数抛异常被catch捕获到当前then方法就是失败的状态promise,下个then就可以直接获取
    faildCallback =  faildCallback instanceof Function ? faildCallback : reason => {throw reason}
    const promise2 = new MyPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        setTimeout(() => {
          try {
            const successCallBackValue = successCallback(this.value)
            resolvePromise(promise2, successCallBackValue, resolve, reject)

          } catch (err) {
            reject(err)
          }
        }, 0);
      } else if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            const faildCallbackReason = faildCallback(this.reason)
            resolvePromise(promise2, faildCallbackReason, resolve, reject)
          } catch (err) {
            // 3. 让当前then为REJECTED
            reject(err)
          }
        }, 0);

      } else {

        this.successCallbackList.push(() => {
          setTimeout(() => {
            try {
              const successCallBackValue = successCallback(this.value)
              resolvePromise(promise2, successCallBackValue, resolve, reject)

            } catch (err) {
              reject(err)
            }
          }, 0);
        })

        this.faildCallbackList.push(() => {
          setTimeout(() => {
            try {
              const faildCallbackReason = faildCallback(this.reason)
              resolvePromise(promise2, faildCallbackReason, resolve, reject)
            } catch (err) {
              reject(err)
            }
          }, 0);
        })
      }
    })
    return promise2
  }
}
function resolvePromise(selfPromise, returnVal, resolve, reject) {
  if (returnVal === selfPromise) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  if (returnVal instanceof MyPromise) {
    returnVal.then(resolve, reject)
  } else {
    resolve(returnVal)
  }
}
const promise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('hello reborn')
  }, 0);
})

promise.then().then().then(res => {
  console.log(res)
})


// 打印结果
// hello reborn

const promise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    reject('no hello reborn')
  }, 0);
})

promise.then().then().then(res => {
  console.log(res)
}, reason => console.log(reason))


// 打印结果
// no hello reborn

三、Promise对象静态方法实现

1. Promise.all

Promise.all 用来解决异步并发问题,接下来我们将分析分析他的特性都有那些 分析

  • promise.all 时promise的静态方法,需要通过static关键字来定义
  • promise接受一个数组作为参数,数组中可以是普通值或是promise对象
  • promise.all 方法返回一个promise对象,至于返回的这个promise对象是成功的,还是失败的取决于数组中所有值的结果。 如果所有的值都是成功的,返回的就是成功的状态,如果有一个是失败的,返回的就是失败的状态。如果promise对象是成功的状态,可以拿得到数组中值的处理结果,结果是按照数组的顺序来的。
  • 数组中值如果是普通值直接直接push到结果集(数组)中,如果是promise对象拿到其promise对象的值push到结果集(数组)中。
// 只展示关键代码
// 根据我们上诉的分析我们可以得到以下代码
  // 1. 定义静态方法
  static all(array) {
    // 3. 定义一个数组用来装数组中值的处理结果
    let results = []
    // 2. 返回一个promise对象
    return new MyPromise((resolve, reject) => {
      // 4. 我们需要用for循环对每一个值都进行处理
      for(let i = 0; i < array.length; i++) {
        // 5. 数组的值有可能是普通数据,也有可能是promise对象,对传进来的值判断。
        if (array[i] instanceof MyPromise) {
          // 7. 如果是promise对象,我们需要通过then方法拿到其结果
          array[i].then(value => results.push(value), reason => reject(reason))
        } else {
          // 6. 对传入的参数不是 promise 对象直接push到数组中
          results.push(array[i])
        }
      }
      // 8. for循环结束之后需要更改promise对象的状态
      resolve(results)
    })
  }
// 测试一波

function p1() {
  return new MyPromise((resolve, reject) => {
    resolve('hello')
  })
}

function p2() {
  return new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve('reborn jiang')
    }, 0)
  })
}
MyPromise.all([p1(), p2(), 1,2,3]).then(value => {
  console.log(value, 'promise.all返回的结果')
})

// 打印结果
// [ 1, 2, 3, 'hello' ] promise.all返回的结果

此时你应该发现这个返回的结果有些问题啊

  • all方法返回的promise对象拿到的结果集的顺序是不对的。
  • 传递给all方法的是5个参数,最后拿到的结果集确实少了一个是异步promise对象p2的结果。 可以先思考下为什么会出现这样的问题。 第二个点我还没有想明白,容我想想再更新文章。

2. Promise.resolve

Promise.resolve方法目的是快速创建一个promise对象 分析

  • Promise.resolve方法是一个静态的方法
  • 他接受一个参数,参数可以是普通值或promise对象。
  • 如果接受是普通值,他就返回一个promise对象,并将这个值作为promise的resolve方法的参数
  • 如果是promise对象就返回这个promise对象
 // 仅展示关键代码
 // 根据上面分析我们可以得到如下代码
static resolve(value) {
    // 1. 如果是promise对象,就返回promise对象
    if (value instanceof MyPromise) return value

    // 2. 普通值的话我们需要创建一个promise对象,将其值最为resolve参数
    return new MyPromise(resolve => resolve(value))
  }

// 测试一波
function p1() {
  return new MyPromise((resolve, reject) => {
    resolve('hello')
  })
}
// 3. 传入普通值
MyPromise.resolve('rrrrbbbb').then(val => {
  console.log(val)
})

// 4. 传入promise对象
MyPromise.resolve(p1()).then(value => {
  console.log(value)
})

// 打印结果如下:
// rrrrbbbb
// hello

3. Promise.reject

与promise.resolve方法同理 Promise.reject 快速创建一个失败的promise对象 分析

  • 静态方法
  • 传递promise对象会抛出异常 UnhandledPromiseRejectionWarning: hello(为promise的resolve,reject接受的值)
  • 普通值返回promise对象并将参数作为reject方法入参 代码很简单,可以自己试试哈~

四、finally方法的实现

finally为在Promise是否成功完成后都需要执行的代码提供了一种方式。 分析:

  • promise方法是promise对象的原型方法
  • finally() 方法返回一个Promise
  • finally()接受一个回调函数作为参数,无论结果是fulfilled或者是rejected,都会执行指定的回调函数
  • finally方法callback如果又异步代码,会等到回调函数执行结束之后,finally返回的promise对象的then方法才会执行。

  // 根据上面分析我们可以得到如下代码
  // 1. 原型方法
  finally(callback) {
    // 2. 无论是fulfilled 还是 rejected 都会执行回调函数,只有then方法知道promise对象的状态

    // 3. 返回一个promise对象,正好then方法就返回promise对象
    return this.then(value => {
      callback()
      return value
    }, reason => {
      callback()
      throw reason
    })
  }
const promise = new MyPromise((resolve, reject) => {
  // resolve('hello reborn')
  reject('hello reborn')
})
// 4. callback 是同步代码时候输出符合目标
promise.finally(() => {
  console.log('finally执行了')
}).then(res => {
  console.log(res)
}, reason => console.log(reason))
// 打印结果
// finally执行了
// hello reborn

// 5. 又异步代码的时候测试结果的时候不符合预期了,
promise.finally(() => {
  setTimeout(() => {
    console.log('finally执行了')
  }, 3000)
}).then(res => {
  console.log(res)
}, reason => console.log(reason))
// 打印结果
// hello reborn
// finally执行了

我们只需要让callback里面的代码执行结束之后,在调用resolve或是reject方法就可以达到目标。 可以借助于Promise.resolve方法

// 根据上面分析我们可以得到如下代码
  // 1. 原型方法
  finally(callback) {
    // 2. 无论是fulfilled 还是 rejected 都会执行回调函数,只有then方法知道promise对象的状态

    // 3. 返回一个promise对象,正好then方法就返回promise对象
    return this.then(value => {
      // 4. 通过resolve方法再调用then得到一个promise对象,最后在将这个通过resolve方法再调用then生成的romise对象返回出去,
      // 最外层的then方法的返回值是promise对象,然后 回取的resolve方法生成的promise对象的结果,将结果作为自己的promise对象resolve的参数
     return MyPromise.resolve(callback()).then(() => value)
      
    }, reason => {
      // 5. resolve方法再调用then得到一个失败promise对象,再将这个对象返回出去。然后外层then回调用返回的promise
      // then方法取到值,调用reject()将值传递。
      return MyPromise.resolve(callback()).then(() => {throw reason})

    })
  }

五、catch方法的实现

catch方法很简单,实际上就是再是再catch方法中调用then方法,不过then方法的第一个参数不传,只传递失败的回调参数。请看下面代码的实现~

// 仅展示关键代码
catch(faildCallback) {
    return this.then(undefined, faildCallback)
  }

promise.then(res => { }).catch(res => {
  console.log(res)
})
// 打印结果
// hello reborn