JavaScript Promis

JavaScript Promis

Promise

解决传统方案回调函数和事件一个新的异步编程解决方案,目前原生Promise已经支持大部分浏览器



目前Promise实现都是遵循Promises/A+规范

Promise 特点

  • Promise内部有三种状态 等待态(Pending)执行态(Fulfilled)拒绝态(Rejected),三种状态转换关系如下:

    • 等待态(Pending)可以迁移至执行态(Fulfilled)拒绝态(Rejected)
    • 执行态(Fulfilled)不能迁移至其他任何状态,必须拥有一个不可变的值(指任何 JavaScript 的合法值)
    • 拒绝态(Rejected)不能迁移至其他任何状态,必须拥有一个不可变的拒绝值(一个 promise 的拒绝原因)
  • Promise内部必须实现then方法,来获取当前值和拒绝值,并且then方法必须返回一个新的Promise对象,需要接受两个函数作为参数onFulfilledonRejected

    • onFulfilledonRejected如果不是函数值会被忽略

    • onFulfilled是函数:

      • promise执行结束后其必须被调用,其第一个参数为promise的终值
      • promise执行结束前其不可被调用
      • 其调用次数不可超过一次
      • 必须作为函数调用并且异步执行
    • onRejected是函数:

      • promise拒绝执行结束后其必须被调用,其第一个参数为promise的拒绝值
      • promise拒绝执行结束前其不可被调用
      • 其调用次数不可超过一次
      • 必须作为函数调用并且异步执行

Promise 基础用法

new Promise((resolve, reject) => {
  setTimeout(() => {
    if(/*成功*/) {
        resolve(1)
    }else {
       reject(2)
    }
  }, 1000)
}).then(
  (data) => {
    // 调用resolve执行
    console.log(data) // 1
  },
  (err) => {
    // 调用reject执行
    console.log(err) // 2
  }
)

实现 Promise

按照Promises/A+规范自己动手实现Promise,结合规范一步步去实现

  • 定义一个Promise构造函数,接受一个函数作为参数,并且该函数立即执行
class XaPromise<T> {
  constructor(executor: Executor<T>) {
    this.initExecutor(executor)
  }
  private initExecutor(executor: Executor<T>) {
    try {
      executor(
        (value) => {
          this.resolve(value)
        },
        (reason) => {
          this.reject(reason)
        }
      )
    } catch (e) {
      this.reject(e)
    }
  }
}
new XaPromise((resolve, reject) => {})
  • Promise内部有三种状态 等待态(Pending)执行态(Fulfilled)拒绝态(Rejected)默认为Pending
type statusType = 'pending' | 'fulfilled' | 'rejected'

class XaPromise<T> {
  ['[[PromiseStatus]]']: statusType = 'pending'
}
  • Promise内部必须实现then方法,并且then方法必须返回一个新的Promise对象
type statusType = 'pending' | 'fulfilled' | 'rejected'

class XaPromise<T> {
  then(onResolve: any, onReject?: any): XaPromise<T> {
    return new XaPromise((resolve, reject) => {})
  }
}
  • Promise对象then方法处理过程
class XaPromise<T> {
  then(onResolve: any, onReject?: any): XaPromise<T> {
    let newXaPromise: any
    // then 方法必须返回一个 promise 对象
    return (newXaPromise = new XaPromise((resolve, reject) => {
      let status = this.getPromiseStatus()
      if (status === 'pending') {
        this.callbacks.push({
          resolve() {
            try {
              // 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程:[[Resolve]](promise2, x)
              let x = onResolve(this.getPromiseValue())
              // 不论 promise1 被 reject 还是被 resolve 时 promise2 都会被 resolve,只有出现异常时才会被 rejected
              this.handlerResolvePromise(newXaPromise, x, resolve, reject)
            } catch (e) {
              // 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e
              reject(e)
            }
          },
          reject() {},
        })
      }
      // 省略部分代码
    }))
  }

  private handlerResolvePromise(newXaPromise: T, x: any, resolve: any, reject: any) {}
}
  • Promise解决过程[[Resolve]](promise2, x)

    • xPromise相等
      • 如果promisex指向同一对象,以TypeError拒绝执行promise
      private handlerResolvePromise(newXaPromise: T, x: any, resolve: any, reject: any) {
          if (x === newXaPromise) {
              return reject(new TypeError('resolve不能传入当前then返回的Promise对象'))
          }
      }
    
    • xPromise
      • 如果x处于等待态,promise需保持为等待态直至x被执行或拒绝
      • 如果x处于执行态,用相同的值执行promise
      • 如果x处于拒绝态,用相同的据因拒绝promise
      private handlerResolvePromise(newXaPromise: T, x: any, resolve: any, reject: any) {
         if (x instanceof XaPromise) {
              // 如果 x 处于等待态, promise 需保持为等待态直至 x 被执行或拒绝
              if (x['[[PromiseStatus]]'] === 'pending') {
                  x.then(
                      (_value: any) => {
                          this.handlerResolvePromise(newXaPromise, _value, resolve, reject)
                      },
                      (_reason: any) => {
                          reject(_reason)
                      }
                  )
              } else {
                  // 如果 x 处于执行态,用相同的值执行 promise
                  // 如果 x 处于拒绝态,用相同的据因拒绝 promise
                  x.then(resolve, reject)
              }
          }
      }
    
    • x为对象或函数

      • x.then赋值给then

      • 如果取x.then的值时抛出错误e ,则以e为据因拒绝promise

      • 如果then是函数,将x作为函数的作用域this调用,传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做rejectPromise

        • 如果resolvePromise以值y为参数被调用,则运行[[Resolve]](promise, y)
        • 如果rejectPromise以据因r为参数被调用,则以据因r拒绝 promise
        • 如果resolvePromiserejectPromise均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
        • 如果调用then方法抛出了异常e
      • 如果then不是函数,以x为参数执行promise

    • 如果x不为对象或者函数,以x为参数执行promise

      private handlerResolvePromise(newXaPromise: T, x: any, resolve: any, reject: any) {
          let flag = false 
          if (typeof x === 'function' || (x !== null && typeof x === 'object')) {
              try {
                  // x 为对象或函数
                  // 把 x.then 赋值给 then
                  // 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
                  let then = x.then
                  // 如果 then 是函数,将 x 作为函数的作用域 this 调用之。传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise
                  if (typeof then === 'function') {
                      then.call(
                          x,
                          (y: any) => {
                              // 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
                              // 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
                              if (flag) return
                              flag = true
                              this.handlerResolvePromise(newXaPromise, y, resolve, reject)
                          },
    
                          (r: any) => {
                              // 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
                              // 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
                              if (flag) return
                              flag = true
                              reject(r)
                          }
                      )
                  } else {
                      // 如果 then 不是函数,以 x 为参数执行 promise
                      reject(x)
                  }
              } catch (e) {
                  // 如果 resolvePromise 或 rejectPromise 已经被调用,则忽略之
                  if (flag) return
                  flag = true
                  reject(e)
              }
          }
      }
    

XaPromise源码地址