Race condition xảy ra khi nhiều tác vụ bất đồng bộ chạy chồng nhau và kết quả phụ thuộc vào cái nào về trước — thứ tự đó không được đảm bảo.
Trường hợp thường gặp: ô tìm kiếm gõ nhanh, phản hồi cũ về sau phản hồi mới và ghi đè kết quả đúng.
javascript
// SAI
async function onType(q) {
const res = await fetch(`/search?q=${q}`)
setResults(await res.json()) // request cũ về muộn sẽ ghi đè
}Ba cách xử lý, theo thứ tự nên dùng:
1. Huỷ request cũ — sạch nhất, còn tiết kiệm băng thông:
javascript
let controller
async function onType(q) {
controller?.abort()
controller = new AbortController()
try {
const res = await fetch(`/search?q=${q}`, { signal: controller.signal })
setResults(await res.json())
} catch (e) {
if (e.name !== 'AbortError') throw e
}
}**2.
Đánh số request, bỏ kết quả không phải mới nhất:**
javascript
let latest = 0
async function onType(q) {
const id = ++latest
const data = await search(q)
if (id !== latest) return // đã có request mới hơn, bỏ kết quả này
setResults(data)
}3. Debounce — giảm số request từ đầu, thường dùng kèm cách 1.
Trong React: cách chuẩn là dọn dẹp trong useEffect:
javascript
useEffect(() => {
let cancelled = false
search(q).then((d) => { if (!cancelled) setResults(d) })
return () => { cancelled = true }
}, [q])