接口竞态条件处理
场景
快速切换 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: 什么是接口竞态?怎么解决?
答案:
竞态是指多个请求并发发出,由于网络延迟不确定,先发出的请求可能后返回,导致用旧数据覆盖了新数据。
解决方案:
- AbortController:取消旧请求(推荐)
- 请求标记:用递增 ID 标记请求,只接受最新 ID 的响应
- TanStack Query / SWR:内置竞态处理