普通视图

发现新文章,点击刷新页面。
今天 — 2025年11月5日首页

封装axios实现全局loading,在一定程度上减少重复请求的发生

作者 apollo_qwe
2025年11月5日 10:51
解决了 “在每个页面 / 按钮上手动绑定 loading” 的问题,大幅减少了重复代码
核心代码如下:
import axios from 'axios';
import { Loading } from 'element-ui';
// 定义不同API类型的超时时间(单位:毫秒)
const TIMEOUT_CONFIG = {
  default: 3000, // 默认超时时间
  fast: 1000,     // 快速API,简单查询等
  normal: 5000,  // 普通API,大多数业务接口
  slow: 10000,    // 慢速API,文件上传、大数据量处理
  critical: 15000 // 关键API,支付、重要业务处理
}

const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, 
  timeout: TIMEOUT_CONFIG.default 
});

/**
 *  loading 计数
 *  loadingCount //请求次数,为0时,结束loading
 **/
 let loadingCount = 0
 let isLoading = false
 let loadingInstance = null
 const noLoadingApi = ['a','b','c'] // 禁止触发全局loading的路由
 const addLoading = (url) => {
 const result = noLoadingApi.includes(url)
  if(result){
    return;
  }
   loadingCount++
   if (!isLoading){
    loadingInstance = Loading.service({
      lock: true,
      background: 'rgba(0, 0, 0, 0.9)'
    })
    isLoading = true
   }
 }
 
 const closeLoading = (url) => {
 const result = url && noLoadingApi.includes(url)
  if(result){
    return;
  }
   loadingCount--
   if (loadingCount <= 0) {
    loadingInstance && loadingInstance.close()
    isLoading = false
   }
 }

service.interceptors.request.use(
  config => {
    // 定义关键API路径数组
    const CRITICAL_API_PATHS = ['a','b','c'];
    
    // 检查是否是关键API
    if (CRITICAL_API_PATHS.some(path => config.url.includes(path))) {
      config.timeout = TIMEOUT_CONFIG.critical
    }
    addLoading(config.url)
    //....根据需求自定义封装请求头
  
    return config;
  },
  error => {
    return Promise.reject(error);
  }
);

service.interceptors.response.use(
  response => {
    closeLoading(response.config.url)
    //...根据需求自定义封装响应头
  },
  error => {
    closeLoading()
    return Promise.reject(error);
  }
);

export default service;

1. 全局统一管理 loading,无需页面 / 按钮单独处理

代码通过 axios 的请求 / 响应拦截器,对所有经过 service 实例的请求进行统一拦截:

  • 请求发起时:自动调用 addLoading 显示全局 loading(除非接口在 noLoadingApi 白名单中);
  • 请求完成时(成功 / 失败):自动调用 closeLoading 关闭全局 loading(当所有并发请求都完成时)。

这种方式下,无论哪个页面、哪个按钮触发的请求,只要使用了这个 service 实例,都不需要在页面中手动写 loading.show() 或 loading.hide(),完全由拦截器自动处理。

2. 避免了 “重复编写 loading 控制逻辑” 的冗余

如果没有这段代码,通常的做法是:

  • 在每个按钮点击事件中,先手动显示 loading;
  • 在请求的 then/catch 中手动隐藏 loading;
  • 还要处理多个请求并发时,loading 被提前关闭的问题(比如两个请求同时发起,第一个完成就关 loading,导致第二个请求无 loading)。

而这段代码通过 loadingCount 计数和拦截器统一控制,一次性解决了 “显示 / 隐藏时机”“并发请求 loading 管理” 等问题,所有页面 / 按钮都能复用这套逻辑,无需重复编写。

3. 特殊场景通过配置排除,灵活性兼顾

代码中通过 noLoadingApi 数组定义了 “不需要 loading 的接口”,对于这些特殊接口,无需在页面中单独处理,只需在全局配置中维护这个数组即可,进一步减少了页面级的重复配置。

总结

这段代码通过 “拦截器 + 全局配置” 的方式,实现了 loading 的 “一次编写,全项目复用”,彻底避免了在每个页面、每个按钮中重复编写 loading 控制逻辑的工作,显著减少了冗余代码,同时还解决了并发请求下的 loading 显示问题,是一种高效的全局状态管理方案。

❌
❌