跳到主要内容

接口竞态条件处理

场景

快速切换 Tab、连续搜索时,后发的请求可能先返回,导致显示的数据不是最新的。

解决方案

AbortController 取消旧请求

React 中处理竞态
function UserProfile({ userId }: { userId: string }) {
const [user, setUser] = useState<User | null>(null);

useEffect(() => {
const controller = new AbortController();

fetch(`/api/users/${userId}`, { signal: controller.signal })
.then((r) => r.json())
.then(setUser)
.catch((e) => {
if (e.name !== 'AbortError') throw e;
});

// userId 变化时,取消上一次请求
return () => controller.abort();
}, [userId]);

return user ? <div>{user.name}</div> : <Loading />;
}

请求标记法(适配不支持取消的场景)

忽略过期响应
function useLatestRequest<T>(fetchFn: () => Promise<T>, deps: unknown[]) {
const [data, setData] = useState<T | null>(null);
const requestIdRef = useRef(0);

useEffect(() => {
const currentId = ++requestIdRef.current;

fetchFn().then((result) => {
// 只接受最新请求的结果
if (currentId === requestIdRef.current) {
setData(result);
}
});
}, deps);

return data;
}

常见面试问题

Q1: 什么是接口竞态?怎么解决?

答案

竞态是指多个请求并发发出,由于网络延迟不确定,先发出的请求可能后返回,导致用旧数据覆盖了新数据。

解决方案:

  1. AbortController:取消旧请求(推荐)
  2. 请求标记:用递增 ID 标记请求,只接受最新 ID 的响应
  3. TanStack Query / SWR:内置竞态处理

相关链接