给axios加把锁

1,676 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情

背景

使用axios调用接口时,接口经过拦截判断到缺少认证身份信息(jwt之类)会有一个调认证接口的操作。就目前不加限制来看,在缺少认证信息的情况下,当前页面并发了6个接口的话,就会调用6次认证接口,属实浪费。那应该如何去优化这个过程呢?

思考

需求1:按正常逻辑来说,无论多少个接口,同一时间都应该只调用一次认证接口才对

需求2:调用认证接口期间,后面发起的接口理应等待认证接口调用完成才继续执行,保证接口都携带上身份信息

综上所述,我们需要一个拥有单例模式+队列的功能,所以这个东西要怎么实现呢?

很简单,那就是Promise,很巧的是,调用axios相应函数会返回一个Promise实例,那么我们只要保存这个返回值,让后续接口到await起来,等到认证接口调用完毕后,才释放接口队列。

let jwt
let lock = null
http.interceptors.request.use(
  async config => {
    // 判断是否有jwt
    if (!jwt) {
      // 生成锁住
      if (!lock) {
        lock = fetchJWT()
      }
      try {
        jwt = await lock // 锁住防止并发
        // 每次并发完成清除Promise
        lock = null
      } catch (e) {
        // 获取jwt失败,跳转登录页重新登录
        login()
      }
    }
    config.headers.Authorization = `Bearer ${jwt}`
    return config
  }
)

原理分解出来后,实现过程就非常简单

题外话

除了axios之外,还有一个叫flyio的库,它自带了lock功能,整体实现方式简单易懂,采取分层设计,让跨端更加简单,感兴趣的可以试下,也可以看看下面分析该库源码的文章

# 阅读flyio源码,一个跨端的http请求库