fetch 還有隱藏技能?——原來它可以被取消!
你大概已經(jīng)用過無數(shù)次 fetch():
const response = await fetch("/api/data");輕輕松松,對吧?
那如果——
- 用戶在請求未完成前跳轉(zhuǎn)頁面?
- 你發(fā)起了新請求,應(yīng)該替換舊請求?
- 想取消一個(gè)長下載或不再需要的網(wǎng)絡(luò)調(diào)用?
多年來,fetch() 沒有“自帶取消”。直到主角登場:AbortController。
AbortController 到底是啥?
AbortController API 能創(chuàng)建一個(gè) signal,把它傳給 fetch,就能隨時(shí)中止一個(gè)或多個(gè)請求。 把它想象成——給你的網(wǎng)絡(luò)請求配了個(gè)遙控器。
const controller = new AbortController();
const signal = controller.signal;
fetch("/api/data", { signal })
.then(res => res.json())
.then(data => console.log(data))
.catch(err => {
if (err.name === "AbortError") {
console.log("Request was cancelled!");
} else {
console.error(err);
}
});
// 需要時(shí)直接取消
controller.abort();?????? 調(diào)用 controller.abort(),請求立刻停止。 ?????? fetch 會以 AbortError 結(jié)束,你可以優(yōu)雅處理。
為什么要取消 fetch?
取消不是“錦上添花”,而是性能與體驗(yàn)必備。真實(shí)場景:
- 搜索框:用戶快速輸入,不能每個(gè)鍵都發(fā)請求
- 分頁/篩選:新篩選發(fā)出,舊結(jié)果應(yīng)作廢
- 導(dǎo)航:離開頁面時(shí),不要讓請求繼續(xù)跑 這些情況下,舊請求是浪費(fèi)帶寬,還可能引發(fā)競態(tài)(舊結(jié)果覆蓋新結(jié)果)。

?? 場景一:用戶手動取消
<button id="cancel">Cancel</button>
<script>
const controller = new AbortController();
const signal = controller.signal;
fetch("https://jsonplaceholder.typicode.com/photos", { signal })
.then(res => res.json())
.then(data => console.log("Fetched:", data))
.catch(err => {
if (err.name === "AbortError") {
console.log("Fetch aborted by user.");
}
});
document.getElementById("cancel").addEventListener("click", () => {
controller.abort();
});
</script>??? 點(diǎn)“Cancel” → 請求立即終止??? catch 分支安全兜底
場景二:新的搜索自動取消舊請求(最常見)
let controller;
async function search(query) {
if (controller) controller.abort(); // 取消舊請求
controller = new AbortController();
try {
const res = await fetch(`/api/search?q=${query}`, {
signal: controller.signal,
});
const data = await res.json();
console.log("Results:", data);
} catch (err) {
if (err.name === "AbortError") {
console.log("Old request aborted!");
} else {
console.error(err);
}
}
}?? 每次新搜索都會自動終止上一次 ?? 避免浪費(fèi)與過期結(jié)果覆蓋
?? 場景三:一把梭取消多個(gè)請求
const controller = new AbortController();
Promise.all([
fetch("/api/user", { signal: controller.signal }),
fetch("/api/posts", { signal: controller.signal }),
]).catch(err => {
if (err.name === "AbortError") {
console.log("All requests aborted.");
}
});
// 一鍵全停
controller.abort();適合儀表盤、批量加載等并發(fā)場景。
Abort 之后會怎樣?
- 同一個(gè) controller 一旦
abort(),就不能復(fù)用;要新建:
controller.abort();
controller = new AbortController(); // 重新開始fetch會立刻以:
{ name: "AbortError", message: "The operation was aborted." }拒絕(reject)所以務(wù)必用 try/catch 或 catch() 正確處理。
兼容性
?? 支持:Chrome 66+、Firefox 57+、Safari 12+、Edge 16+?? 不支持:IE(RIP ??)
別再讓 fetch 為所欲為
AbortController 給了 fetch() 一直缺失的控制力。 無論是搜索、篩選還是各種用戶交互,你都能即時(shí)取消無用請求——省時(shí)間、省流量、避競態(tài)。
記住這句話:
能跑 ≠ 該跑。



























