如何根据用户操作动态调整多个API请求的优先级?

设计师鑫钰 阅读 39

在开发数据表格时同时发起筛选、分页和搜索请求,但关键筛选数据总是最后返回导致界面卡顿。之前尝试用axios.all并发请求,但关键数据因为后端逻辑总是最后回来,有什么办法能让筛选请求优先完成吗?

试过给筛选请求设置超时:timeout: 1000但影响了可靠性。也尝试过手动用axios.CancelToken在新请求到来时取消旧请求,但优先级逻辑写得一团糟,有没有更优雅的方案?


// 当前混乱的尝试
handleSearch() {
  if (this.cancelSearch) this.cancelSearch('新搜索开始')
  const source = axios.CancelToken.source()
  this.cancelSearch = source.cancel
  axios.get('/api/data', { 
    params: this.query,
    cancelToken: source.token 
  }).then(res => {
    // 处理数据
  })
}
我来解答 赞 5 收藏
二维码
手机扫码查看
2 条解答
西门馨月
你这问题我太熟了,之前也踩过这坑——多个请求并发回来,关键的筛选数据慢一拍,前端就得干等,界面卡得像冻僵的企鹅。

核心问题不是并发本身,而是你没把「请求优先级」显式管理起来。axios.all 本质还是谁先到谁先渲染,但你得控制「谁先被处理」,而不是等它自己乱糟糟回来。

我推荐用一个请求管理器,核心思路是:
1. 每个请求带上优先级标识(比如筛选 > 分页 > 搜索)
2. 新请求来时,只取消同级或更低优先级的旧请求
3. 所有响应先不直接更新 UI,而是统一进一个「优先级队列」,按优先级顺序再触发渲染

具体写法:

先封装一个请求控制器,比如叫 RequestManager,里面用一个 Map 存当前活跃的请求,按优先级分组:

const PRIORITY = {
FILTER: 3,
PAGE: 2,
SEARCH: 1
}

class RequestManager {
constructor() {
this.activeRequests = new Map()
}

cancelLowerPriority(priority) {
for (const [key, { cancel, reqPriority }] of this.activeRequests.entries()) {
if (reqPriority < priority) {
cancel(取消低优先级请求: ${key})
this.activeRequests.delete(key)
}
}
}

async request(key, url, config = {}, priority = PRIORITY.SEARCH) {
// 先干掉低优先级的
this.cancelLowerPriority(priority)

// 取消当前同 key 的旧请求(防抖)
if (this.activeRequests.has(key)) {
this.activeRequests.get(key).cancel(新请求覆盖: ${key})
this.activeRequests.delete(key)
}

const source = axios.CancelToken.source()
this.activeRequests.set(key, { cancel: source.cancel, reqPriority: priority })

try {
const res = await axios.get(url, {
...config,
cancelToken: source.token
})
this.activeRequests.delete(key)
return res
} catch (e) {
if (axios.isCancel(e)) {
// 忽略取消错误
return null
}
throw e
}
}
}

// 全局就一个实例
export const requestManager = new RequestManager()


然后在你的组件里用起来:

import { requestManager } from '@/utils/requestManager'

methods: {
async handleFilterChange() {
const res = await requestManager.request(
'filter',
'/api/data',
{ params: { ...this.query, type: 'filter' } },
PRIORITY.FILTER
)
if (res) {
this.updateTable(res.data)
}
},

async handlePageChange(page) {
const res = await requestManager.request(
'page_' + page,
'/api/data',
{ params: { ...this.query, page } },
PRIORITY.PAGE
)
if (res) {
this.updatePagination(res.data)
}
},

async handleSearch() {
const res = await requestManager.request(
'search',
'/api/data',
{ params: { ...this.query, keyword: this.keyword } },
PRIORITY.SEARCH
)
if (res) {
this.updateTable(res.data)
}
}
}


这么写有几个好处:
- 筛选请求一来,立刻取消掉旧的筛选、分页、搜索请求,避免旧数据乱入
- 新的筛选请求进来,会立刻中断,不会等它慢慢跑完再回来
- 逻辑清晰,加个新优先级(比如导出、预加载)也容易扩展

要是你后端真能配合就更稳——比如筛选接口单独走一个高优先级的微服务,但前端先这么兜底,效率更高。

别再用 timeout 抗风险了,那玩意儿纯属掩耳盗铃,迟早出事。
点赞 3
2026-02-23 18:11
UP主~瑞丽
用请求队列控制优先级,关键筛选单独处理。代码如下:

class ApiQueue {
constructor() {
this.queue = []
this.processing = false
}

add(request, priority = 0) {
const item = { request, priority }
this.queue.push(item)
this.queue.sort((a, b) => b.priority - a.priority)
this.run()
}

run() {
if (this.processing) return
const next = this.queue.shift()
if (!next) return

this.processing = true
next.request().finally(() => {
this.processing = false
this.run()
})
}
}

const apiQueue = new ApiQueue()

// 使用方式
apiQueue.add(() => axios.get('/api/filter', { params: filterParams }), 1) // 高优先级
apiQueue.add(() => axios.get('/api/search', { params: searchParams }), 0) // 普通优先级

搞定
点赞 7
2026-02-14 16:11