# 实现一个Promise

# 基本原理:

  • Promise 是一个类,在执行这个类的时候会传入一个执行器,这个执行器会立即执行
  • Promise 会有三种状态
    • Pending 等待
    • Fulfilled 完成
    • Rejected 失败
  • 状态只能由 Pending --> Fulfilled 或者 Pending --> Rejected,且一但发生改变便不可二次修改;
  • Promise 中使用 resolve 和 reject 两个函数来更改状态;
    • then 方法内部做但事情就是状态判断
    • 如果状态是成功,调用成功回调函数
    • 如果状态是失败,调用失败回调函数

# 定义状态

加强版

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

// 新建MyPromise类
class MyPromise {
  constructor(executor) {
    // executor是一个执行器, 进入会立即执行
    // 并传入resolve和reject方法
    try {
      executor(this.resolve, this.reject)
    } catch (error) {
      // 如果有错误,就直接执行 reject
      this.reject(error)
    }
  }

  // 储存状态的变量,初始值是 pending
  status = PENDING

  // 成功之后的值
  value = null;

  // 失败之后的原因
  reason = null;

  // 存储成功回调函数
  onFulfilledCallback = [];

  // 存储失败回调函数
  onRejectedCallback = [];

  // resolve和reject为什么要用箭头函数?
  // 如果直接调用的话,普通函数this指向的是window或者undefined
  // 用箭头函数就可以让this指向当前实例对象

  // 更改成功后的状态
  resolve = (value) => {
    // 只有状态是等待, 才执行状态修改
    if (this.status == PENDING) {
      // 状态修改为成功
      this.status = FULFILLED
      // 保存成功之后的值
      this.value = value

      // resolve里面将所有成功的回调拿出来执行
      while (this.onFulfilledCallback.length) {
        this.onFulfilledCallback.shift()(value)
      }
    }
  }

  // 更改失败后的状态
  resolve = (reason) => {
    // 只有状态是等待,才执行状态修改
    if (this.status === PENDING) {
      // 状态成功为失败
      this.status = REJECTED
      // 保存失败后的原因
      this.reason = reason

      // resolve里面将所有失败的回调拿出来执行
      while (this.onRejectedCallback.length) {
        this.onRejectedCallback.shift()(reason)
      }
    }
  }

  // then的实现
  then(onFulfilled, onRejected) {
    // 判断状态
    if (this.status === FULFILLED) {
      // 调用成功回调,并且把原因返回
      onFulfilled(this.value)
    } else if(this.status === REJECTED) {
      // 调用失败回调,并且把原因返回
      onRejected(this.reason)
    } else if (this.status === PENDING) { // 处理异步
      // 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来
      // 等到执行成功失败函数的时候再传递
      this.onFulfilledCallback.push(onFulfilled)
      this.onRejectedCallback.push(onRejected)
    }

    // 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去
    const promise2 = new MyPromise((resolve, reject) => {
      // 这里的内容在执行器中,会立即执行
      if (this.status === FULFILLED) {
        // 创建一个微任务等待 promise2 完成初始化
       queueMicrotask(() => {
         try {
          // 获取成功回调函数的执行结果
          const x = onFulfilled(this.value)
          // 传入 resolvePromise 集中处理
          resolvePromise(x, resolve, reject)
         } catch(error) {
           reject(error)
         }
       })
      } else if (this.status === REJECTED) {
        queueMicrotask(() => {
          try {
            // 调用失败回调,并且把原因返回
            const x = onRejected(this.reason)
            resolvePromise(promise2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.status === PENDING) {
        // 等待
      // 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来
      // 等到执行成功失败函数的时候再传递
        this.onFulfilledCallback.push(onFulfilled)
        this.onRejectedCallback.push(onRejected)
      }
    })

    return promise2
  } 
  
}

function resolvePromise(x, resolve, reject) {
  // 如果相等了,说明return的是自己,抛出类型错误并返回
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  // 判断x是不是 MyPromise 实例对象
  if (x instanceof MyPromise) {
    // 执行 x,调用 then 方法,目的是将其状态变为 fulfilled 或者 rejected
    // x.then(value => resolve(value), reason => reject(reason))
    // 简化之后
    x.then(resolve, reject)
  } else {
    resolve(x)
  }
}

module.exports = MyPromise

基础面试版

function myPromise(constructor) {
  let self = this
  self.status = 'pending' //定义状态改变前的初始状态
  self.value = undefined // 定义状态为resolved的时候的状态
  self.reason = undefined //定义状态为rejected的时候的状态

  function resolve(value) {
    //两个==="pending",保证了状态的改变是不可逆的
    if (self.status === 'pending') {
      self.value = value
      self.status = 'resolved'
    }
  }

  function reject(reason) {
    //两个==="pending",保证了状态的改变是不可逆的
    if (self.status === 'pending') {
      self.reason = reason
      self.status = 'reject'
    }
  }

  // 捕获构造异常
  try {
    constructor(resolve, reject)
  } catch (e) {
    reject(e)
  }
}

myPromise.prototype.then = function(onFullFilled, onRejected) {
  let self = this
  switch(self.status) {
    case 'resolve':
      onFullFilled(self.value)
      break
    case 'rejected':
      onRejected(self.reason)
      break
    default:
  }
}