ES6 | 手写Promise

295 阅读3分钟

1、Promise 的声明

首先声明定义类并声明Promise状态与值。

  • 使用静态属性保存状态值
  • Promise存在三个状态(state)pending、fulfilled、rejected
  • pending(等待态)为初始态,并可以转化为fulfilled(成功态)和rejected(失败态)
  • 成功时,不可转为其他状态,且必须有一个不可改变的值(value)
  • 失败时,不可转为其他状态,且必须有一个不可改变的原因(reason)
  • executor函数为执行者
  • 当执行者出现异步时触发拒绝状态
  • 因为resolvereject方法在executor中调用,作用域也是executor作用域,这会造成this指向window,现在使用的是class定义(class默认使用严格模式),this为undefined
class DPromise {
  static PENDING = 'pending' // 准备状态
  static FULFILLED = 'fulfilled' // 完成状态
  static REJECTED = 'rejected' // 拒绝状态

  constructor(executor) {
    this.state = DPromise.PENDING
    this.value = null
    try {
      executor(this.resolve.bind(this), this.reject.bind(this))
    } catch (error) {
      this.reject(error)
    }
  }
  resolve(value) {
    if (this.state == DPromise.PENDING) {
      this.state = DPromise.FULFILLED
      this.value = value
    }
  }
  reject(value) {
    if (this.state == DPromise.PENDING) {
      this.state = DPromise.REJECTED
      this.value = value
    }
  }
}

2、THEN方法

  • 当状态state为fulfilled,则执行onFulfilled,传入this.value。当状态state为rejected,则执行onRejected,传入this.reason
  • onFulfilled, onRejected如果他们是函数,则必须分别在fulfilled,rejected后被调用,value或reason依次作为他们的第一个参数
then(onFulfilled, onRejected) {
  if (typeof onFulfilled != 'function') {
    onFulfilled = value => value
  }
  if (typeof onRejected != 'function') {
    onRejected = value => value
  }
  if (this.state == DPromise.FULFILLED) {
    try {
      onFulfilled(this.value)
    } catch (error) {
      onRejected(error)
    }
  }
  if (this.state == DPromise.REJECTED) {
    try {
      onRejected(this.value)
    } catch (error) {
      onRejected(error)
    }
  }
}

3、异步任务

  • 使用setTimeout来将onFulfilledonRejected做为异步宏任务执行
then(onFulfilled, onRejected) {
  if (typeof onFulfilled != 'function') {
    onFulfilled = value => value
  }
  if (typeof onRejected != 'function') {
    onRejected = value => value
  }
  if (this.state == DPromise.FULFILLED) {
    setTimeout(() => {
      try {
        onFulfilled(this.value)
      } catch (error) {
        onRejected(error)
      }
    })
  }
  if (this.state == DPromise.REJECTED) {
    setTimeout(() => {
      try {
        onRejected(this.value)
      } catch (error) {
        onRejected(error)
      }
    })
  }
}

4、PENDING状态

  • 在构造函数中添加callbacks来保存pending状态时处理函数,当状态改变时循环调用
constructor(executor) {
  ...
  this.callbacks = []
  ...
} 
  • 在then方法中添加保存执行函数到callbacks数组中
then(onFulfilled, onRejected) {
  if (typeof onFulfilled != 'function') {
    onFulfilled = value => value
  }
  if (typeof onRejected != 'function') {
    onRejected = value => value
  }
	if (this.state == DPromise.PENDING) {
    this.callbacks.push({
      onFulfilled: value => {
        try {
          onFulfilled(value)
        } catch (error) {
          onRejected(error)
        }
      },
      onRejected: value => {
        try {
          onRejected(value)
        } catch (error) {
          onRejected(error)
        }
      }
    })
  }
  ...
}
  • resovlereject中添加处理callback方法的代码
resolve(value) {
  if (this.state == DPromise.PENDING) {
    this.state = DPromise.FULFILLED
    this.value = value
    this.callbacks.map(callback => {
      callback.onFulfilled(value)
    })
  }
}
reject(value) {
  if (this.state == DPromise.PENDING) {
    this.state = DPromise.REJECTED
    this.value = value
    this.callbacks.map(callback => {
      callback.onRejected(value)
    })
  }
}

5、PENDING异步

  • 解决以上问题,只需要将resolvereject执行通过setTimeout定义为异步任务
resolve(value) {
  if (this.state == DPromise.PENDING) {
   	this.state = DPromise.FULFILLED
		this.value = value
    setTimeout(() => {
      this.callbacks.map(callback => {
        callback.onFulfilled(value)
      })
    })
  }
}
reject(value) {
  if (this.state == DPromise.PENDING) {
  	this.state = DPromise.REJECTED
    this.value = value
    setTimeout(() => {
      this.callbacks.map(callback => {
        callback.onRejected(value)
      })
    })
  }
}

6、链式操作

  • then的onReject函数是对前面Promise的rejected的处理
  • 但该Promise返回状态要为fulfilled,所以在调用onRejected后改变当前Promise为fulfilled状态
then(onFulfilled, onRejected) {
  if (typeof onFulfilled != 'function') {
    onFulfilled = value => value
  }
  if (typeof onRejected != 'function') {
    onRejected = value => value
  }
  return new DPromise((resolve, reject) => {
    if (this.state == DPromise.PENDING) {
      this.callbacks.push({
        onFulfilled: value => {
          try {
            let result = onFulfilled(value)
            resolve(result)
          } catch (error) {
            reject(error)
          }
        },
        onRejected: value => {
          try {
            let result = onRejected(value)
            resolve(result)
          } catch (error) {
            reject(error)
          }
        }
      })
    }
    if (this.state == DPromise.FULFILLED) {
      setTimeout(() => {
        try {
          let result = onFulfilled(this.value)
          resolve(result)
        } catch (error) {
          reject(error)
        }
      })
    }
    if (this.state == HD.REJECTED) {
      setTimeout(() => {
        try {
          let result = onRejected(this.value)
          resolve(result)
        } catch (error) {
          reject(error)
        }
      })
    }
  })
}

7、完整代码

/**
 * DPromise完整代码
 */
class DPromise {
  static PENDING = 'pending' // 准备状态
  static FULFILLED = 'fulfilled' // 完成状态
  static REJECTED = 'rejected' // 拒绝状态

  constructor(executor) {
    this.state = DPromise.PENDING
    this.value = null
    this.callbacks = [] // 保存pending状态时处理函数,当状态改变时循环调用
    // resolve或rejected方法在executor中调用,作用域也是executor作用域,这会造成this指向window,现在使用的是class定义(class默认使用严格模式),this为undefined
    try {
      executor(this.resolve.bind(this), this.reject.bind(this))
    } catch(error) {
      this.reject(error)
    }
  }
  resolve(value) {
    if (this.state == DPromise.PENDING) {
      this.state = DPromise.FULFILLED
      this.value = value
      setTimeout(() => {
        this.callbacks.map(callback => {
          callback.onFulfilled(value)
        })
      })
    }
  }
  reject(value) {
    if (this.state == DPromise.PENDING) {
      this.state = DPromise.REJECTED
      this.value = value
      setTimeout(() => {
        this.callbacks.map(callback => {
          callback.onRejected(value)
        })
      })
    }
  }
  // 处理状态的改变
  then(onFulfilled, onRejected) {
    if (typeof onFulfilled != 'function') {
      onFulfilled = value => value
    }
    if (typeof onRejected != 'function') {
      onRejected = value => value
    }
    // 实现.then链式调用
    let promise = new DPromise((resolve, reject) => {
      // 当实例使用异步调用resolve方法,统一处理pending状态
      if (this.state == DPromise.PENDING) {
        this.callbacks.push({
          onFulfilled: value => {
            this.parse(promise, onFulfilled(this.value), resolve, reject)
          },
          onRejected: value => {
            this.parse(promise, onRejected(this.value), resolve, reject)
          }
        })
      }
      if (this.state == DPromise.FULFILLED) {
        // 使用setTimeout异步宏任务执行
        setTimeout(() => {
          this.parse(promise, onFulfilled(this.value), resolve, reject)
        })
      }
      if (this.state == DPromise.REJECTED) {
        // 使用setTimeout异步宏任务执行
        setTimeout(() => {
          this.parse(promise, onRejected(this.value), resolve, reject)
        })
      }
    })
    return promise
  }
  parse(promise, result, resolve, reject) {
    // 返回约束,then的返回的promise不能是then相同的Promise
    if (promise == result) {
      throw new TypeError('Chaining cycle detected for promise')
    }
    try {
      // 判断分别处理返回值为Promise与普通值的情况
      if (result instanceof DPromise) {
        result.then(resolve, reject)
      } else {
        resolve(result)
      }
    } catch(error) {
      reject(error)
    }
  }
  static resolve(value) {
    return new DPromise((resolve, reject) => {
      if (value instanceof DPromise) {
        value.then(resolve, reject)
      } else {
        resolve(value)
      }
    })
  }
  static reject(reason) {
    return new DPromise((_, reject) => {
      reject(reason)
    })
  }
  static all(promises) {
    let resolves = []
    return new DPromise((resolve, reject) => {
      promises.forEach(promise => {
        promise.then(
          value => {
            resolves.push(value)
            if (resolves.length == promises.length) {
              resolve(resolves)
            }
          },
          reason => {
            reject(reason)
          }
        )
      })
    })
  }
  static race(promises) {
    return new DPromise((resolve, reject) => {
      promises.map(promise => {
        promise.then(value => {
          resolve(value)
        })
      })
    })
  }
}