什么是请求竞态?
- 请求竞态(Race Condition)是指在前端开发中,当多个异步请求(如 AJAX、Fetch 或 Axios 请求)同时发起时,由于网络延迟或服务器响应时间不同,导致后发起的请求可能比先发起的请求更早返回,从而使得最终显示的数据不符合预期顺序。
- 简而言之就是:接口的请求顺序不一定等于接口的返回顺序。
- 例如下图
当我快速点击按钮1、按钮2时,由于接口的响应速度不一定一样,因此导致页面上显示的是page1,这就是一个典型的请求竞态

如何解决?
解决这个问题,我这里提供两种方案:
- 前端每次发送请求时都带一个requestId给后端,后端返回结果时也把这个requestId返回过来,接口响应数据后,请端通过最后一次都requestId来找到后端最新的接口返回的数据,这种方案有个缺点就是需要去动服务端。
- 纯前端利用abort来取消请求,每次发送请求时先判断上一次是不是请求过相同的接口了,如果有就取消上一次的请求。
这里简单提一下一些ajax取消请求的方法
- xhr利用abort()取消
2.fetch利用AbortController

由于现在的项目大多都是用axios,因此我这里讲axios如何取消请求
js
import axios from 'axios'
const requestMap = new Map()
const pushRequest = (config) => {
const { url2, method } = config
const uniq = `${url2}_${method}` // 自行调整
// 当我们每次发起请求时,先去map中找是否有相同的请求,如果有则讲上一次的请求取消掉
if (!requestMap.has(uniq)) {
const controller = new AbortController()
config.signal = controller.signal
requestMap.set(uniq, controller)
} else {
const controller = requestMap.get(uniq)
controller.abort() // 取消请求
requestMap.delete(uniq) // 删除controller
}
}
const removeRequest = (config) => {
const { url2, method } = config
const uniq = `${url2}_${method}`
if (requestMap.has(uniq)) {
requestMap.delete(uniq)
}
}
const request = axios.create({
baseURL: 'http://localhost:12306/',
})
try {
request.interceptors.request.use(
(config) => {
pushRequest(config)
console.log('map', requestMap)
console.log('Request Interceptor', config)
return config
},
(err) => {
console.log('Request Error', err)
return Promise.reject(err)
},
)
} catch (error) {
console.log('Request Error', error)
}
request.interceptors.response.use(
(response) => {
removeRequest(response.config)
console.log('Response Interceptor', requestMap)
return response
},
(err) => {
return Promise.reject(err)
},
)
export default request