状态机模式 与 ajax 的结合运用

太神奇了,昨晚做了个梦,梦中我悟出一个道理:凡是涉及到异步操作而且需要返回值的函数,一定要封装成 Promise 的形式,假如返回值取决于多个异步操作的结果,那么需要对每个异步操作进行状态的设计,而且需要封装一个 next 函数。😂😂😂,到了晚上才觉到很有意思,所以结合 ajax 设置最短返回时间和最大返回时间进行实践:

  const PENDING = 'PENDING'
  const RESOLVED = 'RESOLVED'
  const REJECTED = 'REJECTED'
  const FULLFILLED = 'FULLFILLED'

  /**
   * @desc 异步操作模拟
   * @param time 响应时间
   * @param isError 是否抛错
   */
  const mock = (time, isError) => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (!isError) {
          resolve({ user: 'ManbaX' })
        } else {
          reject('request error')
        }
      }, time)
    })
  }

  /**
   * @desc 生产不同类型请求的工厂函数
   * @param time 响应时间
   * @param isError 是否抛错
   */
  var RequestFactory = function (time, isError) {
    var request = function () {
      return new Promise((resolve, reject) => {
        var min = PENDING
        var max = PENDING
        var state = PENDING
        var res = null

        var next = function (name) {
          const cb = function () {
            if (state === RESOLVED) {
              resolve(res)
            } else {
              reject(res)
            }
          }
          if (name === 'res' && min === FULLFILLED) {
            cb()
          }

          if (name === 'min' && (state === RESOLVED || state === REJECTED)) {
            cb()
          }

          if (name === 'max' && state === PENDING) {
            reject('timeout')
          }
        }

        setTimeout(() => {
          min = FULLFILLED
          next('min')
        }, 500)

        setTimeout(() => {
          max = FULLFILLED
          next('max')
        }, 1000)

        mock(time, isError).then(data => {
          res = data
          state = RESOLVED
          next('res')
        }).catch(error => {
          res = error
          state = REJECTED
          next('res')
        })
      })
    }

    return request
  }

  // 不超时, 不返回错误
  console.time('r1')
  RequestFactory(200)().then(res => {
    console.log('data: ', res)
  }).finally(() => {
    console.timeEnd('r1')
  })
  
  // 不超时, 返回错误
  console.time('r2')
  RequestFactory(200, true)().catch(err => {
    console.log('error', err)
  }).finally(() => {
    console.timeEnd('r2')
  })

  // 超时
  console.time('r3')
  RequestFactory(2000)().catch(res => {
    console.log('error: ', res)
  }).finally(() => {
    console.timeEnd('r3')
  })

上面的运行结果符合预期,本来梦中还有另外一个有意思的东西,但是太模糊了就搞忘记了,下次一定早点记录。

posted on 2020-06-26 23:16  manbax  阅读(374)  评论(4编辑  收藏  举报