如何判断所有异步HTTP请求都已完成并实现加载指示器功能
解决方案
核心思路是维护全局的活跃请求计数器,配合防抖逻辑避免多批请求间隙的加载指示器闪烁。
具体实现步骤
- 第一步:定义全局状态变量
// 全局活跃请求计数 let activeRequestCount = 0 // 隐藏加载器的延迟定时器id let hideLoaderTimer = null // 加载指示器DOM节点,可替换为自己的节点选择逻辑 const loader = document.querySelector('#loading-indicator') // 防抖延迟时间,单位ms,根据业务场景调整,一般100-300ms足够避免闪烁 const HIDE_DELAY = 200
- 第二步:封装请求拦截逻辑,自动更新计数
如果你使用的是fetch,可以直接封装全局的fetch方法:
const originalFetch = window.fetch window.fetch = async (...args) => { // 发起请求前计数+1,显示加载器 activeRequestCount++ if (activeRequestCount > 0) { // 清除之前的隐藏定时器,避免刚显示就被隐藏 if (hideLoaderTimer) clearTimeout(hideLoaderTimer) loader.style.display = 'block' } try { const response = await originalFetch(...args) return response } catch (err) { // 错误正常抛出,不影响原有业务的错误处理 throw err } finally { // 请求完成(无论成功失败)计数-1 activeRequestCount-- if (activeRequestCount === 0) { // 延迟隐藏,避免多批请求间隙闪烁 hideLoaderTimer = setTimeout(() => { loader.style.display = 'none' }, HIDE_DELAY) } } }
如果你使用的是XMLHttpRequest,可以用类似的方式封装原型上的open方法:
const originalOpen = XMLHttpRequest.prototype.open XMLHttpRequest.prototype.open = function (...args) { activeRequestCount++ if (activeRequestCount > 0) { if (hideLoaderTimer) clearTimeout(hideLoaderTimer) loader.style.display = 'block' } this.addEventListener('loadend', () => { activeRequestCount-- if (activeRequestCount === 0) { hideLoaderTimer = setTimeout(() => { loader.style.display = 'none' }, HIDE_DELAY) } }) originalOpen.apply(this, args) }
方案优势
- 不需要手动维护请求数组,所有请求自动被拦截计数,无论是第一批还是后续依赖触发的新请求,都会被统计到
- 防抖逻辑避免了两批请求之间加载指示器短暂消失再出现的闪烁问题
- 完全不侵入原有业务代码,不需要修改现有请求逻辑,引入即可生效
注意事项
- 如果有部分请求不需要触发加载指示器(比如后台心跳请求),可以在封装逻辑里加白名单判断,比如匹配请求url的关键词,符合要求的请求就不更新计数
- 延迟时间可以根据业务场景调整,如果两批请求的间隙普遍较长,可以适当调大延迟值
内容的提问来源于stack exchange,提问作者key
相关产品推荐
相关产品推荐

