标准答案
- 竞态场景通常发生在搜索、筛选、分页、路由切换和快速重复提交中,旧请求可能比新请求更晚返回。
- 可以用 AbortController 取消旧请求,也可以用 requestId 或 token 判断返回结果是否仍然有效。
- watch 发起请求时,要利用 cleanup 在依赖变化前取消上一次请求或标记上一次结果失效。
- 组件卸载时要停止定时器、事件监听、订阅和未完成请求,避免更新已卸载组件状态。
- 请求层和页面层要分工清楚:请求层处理取消能力和错误规范,页面层处理当前业务是否仍需要这次结果。
题目解析
这道题的关键是“旧结果不能覆盖新状态”。只写 loading true/false 很容易在并发请求下出错。
AbortController 更适合支持取消的 fetch 请求;token 判断适合接口库不支持取消或只需要忽略旧结果的场景。
组件卸载后的状态更新在 Vue 里不一定总是直接报错,但仍然会造成无意义逻辑、错误提示错位或内存泄漏。
代码示例
下面用 AbortController 和 watch cleanup 处理搜索请求竞态。
TypeScript
watch(
keyword,
async (value, _oldValue, onCleanup) => {
const controller = new AbortController()
onCleanup(() => controller.abort())
loading.value = true
try {
result.value = await fetchSearch(value, {
signal: controller.signal
})
} finally {
if (!controller.signal.aborted) {
loading.value = false
}
}
}
)常见误区
- 快速切换筛选条件时没有处理旧请求,导致页面显示过期数据。
- 组件卸载后请求仍然回写状态,造成提示错位或无意义更新。
- 只取消请求,没有处理 loading、error 和空态在取消后的表现。