JavaScript AbortController 撤銷非同步任務
在現代 JavaScript 開發中,處理非同步任務(如 API 請求)是家常便飯。然而,有時候我們會需要「取消」已經發出但尚未完成的任務——例如當使用者在切換頁面後,原本舊頁面的 API 請求就應該被中斷,以節省網路資源。
AbortController 正是為了解決這個需求而誕生的標準方法。
基本概念:Controller 與 Signal
AbortController 包含兩個核心部分:
- 實例 (The Controller): 它是發號施令的人,擁有一個
abort()方法。 - 信號 (The Signal): 它是訊息傳遞者 (
controller.signal),會被傳遞給想要監聽「取消指令」的非同步任務。
取消 Fetch 請求
這是 AbortController 最常見的應用場景。
const controller = new AbortController();
const signal = controller.signal;
fetch('https://api.example.com/data', { signal })
.then((response) => response.json())
.then((data) => console.log(data))
.catch((err) => {
if (err.name === 'AbortError') {
console.log('請求已被手動取消');
} else {
console.error('發生其他錯誤', err);
}
});
// 當你想取消請求時:
controller.abort();
自動超時中斷 (AbortSignal.timeout)
在 2024-2025 年的標準中,瀏覽器引入了更簡潔的超時處理方式:AbortSignal.timeout(ms)。它會自動在指定毫秒後發出取消信號。
// 設定 5 秒後自動超時取消
fetch('/long-api-call', { signal: AbortSignal.timeout(5000) }).catch((err) => {
if (err.name === 'TimeoutError') {
console.log('連線超時了');
}
});
一次清除多個 Event Listeners
AbortController 不僅能用於 Fetch,還能用來清理事件監聽器。這在 Single Page Application (SPA) 中非常有用,能有效防止記憶體洩漏。
const controller = new AbortController();
window.addEventListener(
'scroll',
() => {
console.log('捲動中...');
},
{ signal: controller.signal }
);
window.addEventListener(
'resize',
() => {
console.log('縮放中...');
},
{ signal: controller.signal }
);
// 當元件卸載 (Unmount) 時,一併清除上述所有監聽器:
controller.abort();
同時監聽多個信號 (AbortSignal.any)
有時候一個任務可能因為「多種原因」而取消(例如:使用者點擊取消按鈕 或 超時),這時可以使用 AbortSignal.any()。
const userCancel = new AbortController();
const timeoutSignal = AbortSignal.timeout(3000);
//只要其中一個信號觸發,請求就會中斷
fetch('/api', {
signal: AbortSignal.any([userCancel.signal, timeoutSignal]),
});
實作自己的「可撤銷」函式
你也可以在自定義的異步函式或 Promise 中支援 AbortSignal。
function myTask(signal) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => resolve('完成!'), 5000);
// 監聽外部傳來的取消事件
signal.addEventListener('abort', () => {
clearTimeout(timer);
reject(new Error('任務被中止了'));
});
});
}
結語
AbortController 是目前 JavaScript 取消行為的正式標準。它不僅統一了 API 請求的中斷方式,還擴展到了事件管理等多個領域。學會使用它,能讓你的應用程式資源管理變得更加專業且優雅。
相關閱讀: