问题来源

由于查询条件改变频率高,或者后端数据处理逻辑复杂,导致接口返回的顺序跟实际请求的顺序不一致

如:同一接口,先用复杂度高的查询条件发A请求,然后在A还没返回时发简单的B请求,且B返回数据后A才返回,此时若是用 *.then(res => …) 来处理的话,会出现最终使用的是A的返回数据的情况。

解决思路

由于涉及的场景不算复杂,故不打算使用类,个人选择了工厂函数的模式,考虑用两个变量分别保存当前已发送的请求数量,及当前请求的索引,分别记为A,B

A初始为0,每次请求时加一,并将A赋值给该请求的索引B,请求返回时对比A和B,则:

  1. A > B,说明不是我们期望的请求,在返回的数据中作标记,并在请求返回的回调函数中进一步处理
  2. A = B,说明是我们应该处理的请求,将A置为0并返回原数据即可

正确的实现不应该出现 A < B 的情况

代码

/** 例如:
 * const fetchOptions = limitRequest()
 * fetchOptions({ url: 'http://www.baidu.com' }).then(res => { console.log(res) })
**/
const limitRequest = function() {
  const num = new Map() // 请求数量
  num.set('_default', 0) // 默认情况
  return function(reqObj, requestKey = '_default') { // requestKey为请求的唯一标识符,当需要标识不同请求进行拦截时必传
    if (!num.has(requestKey)) { num.set(requestKey, 0) } // 若key不存在则设置
    const keyNum = num.get(requestKey) + 1 // 每次调用请求数量加一
    num.set(requestKey, keyNum) // 更新map请求数量
    const idx = keyNum // 请求索引
    return request(reqObj).then(res => {
      if (num.get(requestKey) === idx) {
        num.set(requestKey, 0)
      } else { res._beIntercepted = true }
      return res
    }).catch(err => Promise.reject(err))
  }
}

注:代码中除了实现上述逻辑之外,还用hash表标记了期望处理的不同请求,这样可以避免为每个期望处理的请求都调用一次工厂函数

Leave a Reply

Your email address will not be published. Required fields are marked *