一文深入詳解Axios請(qǐng)求取消機(jī)制
Axios是否真的支持取消請(qǐng)求呢
是的,Axios 完全支持取消請(qǐng)求。
Axios 提供了兩種主要的取消請(qǐng)求的方式:
- 使用
AbortController(推薦,現(xiàn)代瀏覽器和 Node.js 環(huán)境) - 使用
CancelToken(舊版方式,Axios 0.22.0 之前的主要方式,現(xiàn)在已廢棄但仍兼容)
1. 使用AbortController(推薦)
AbortController 是 Web 標(biāo)準(zhǔn) API,用于中止一個(gè)或多個(gè) Web 請(qǐng)求。Axios 從 v0.22.0 開(kāi)始支持它,并推薦使用這種方式。
示例代碼:
import axios from 'axios';
// 1. 創(chuàng)建一個(gè) AbortController 實(shí)例
const controller = new AbortController();
const signal = controller.signal; // 獲取 AbortSignal 對(duì)象
// 2. 在 Axios 請(qǐng)求配置中傳入 signal
axios.get('/api/data', { signal })
.then(response => {
console.log('請(qǐng)求成功:', response.data);
})
.catch(error => {
// 檢查錯(cuò)誤是否是由于請(qǐng)求取消引起的
if (axios.isCancel(error)) {
console.log('請(qǐng)求被取消:', error.message);
} else {
console.log('請(qǐng)求發(fā)生錯(cuò)誤:', error.message);
}
});
// 3. 在需要取消請(qǐng)求時(shí)調(diào)用 controller.abort()
// 例如,在組件卸載時(shí),或者用戶點(diǎn)擊了取消按鈕時(shí)
setTimeout(() => {
controller.abort(); // 這會(huì)觸發(fā) signal 上的 abort 事件,Axios 會(huì)捕獲并取消請(qǐng)求
console.log('請(qǐng)求已嘗試取消');
}, 100); // 100ms 后取消請(qǐng)求
優(yōu)點(diǎn):
- 是 Web 標(biāo)準(zhǔn) API,不僅限于 Axios,也可以用于
fetchAPI 或其他支持AbortSignal的異步操作。 - 更現(xiàn)代、更簡(jiǎn)潔的 API 設(shè)計(jì)。
- 可以取消多個(gè)請(qǐng)求(將同一個(gè)
signal傳遞給多個(gè)請(qǐng)求)。
2. 使用CancelToken(舊版,已廢棄但仍兼容)
CancelToken 是 Axios 早期提供的取消請(qǐng)求機(jī)制。雖然現(xiàn)在推薦使用 AbortController,但如果你在使用舊版本的 Axios 或者需要兼容舊代碼,它仍然可用。
示例代碼:
import axios from 'axios';
// 1. 創(chuàng)建一個(gè) CancelToken.Source 工廠函數(shù)
const CancelToken = axios.CancelToken;
const source = CancelToken.source(); // source 對(duì)象包含 token 和 cancel 方法
// 2. 在 Axios 請(qǐng)求配置中傳入 token
axios.get('/api/data', { cancelToken: source.token })
.then(response => {
console.log('請(qǐng)求成功:', response.data);
})
.catch(error => {
// 檢查錯(cuò)誤是否是由于請(qǐng)求取消引起的
if (axios.isCancel(error)) {
console.log('請(qǐng)求被取消:', error.message);
} else {
console.log('請(qǐng)求發(fā)生錯(cuò)誤:', error.message);
}
});
// 3. 在需要取消請(qǐng)求時(shí)調(diào)用 source.cancel()
// 例如,在組件卸載時(shí),或者用戶點(diǎn)擊了取消按鈕時(shí)
setTimeout(() => {
source.cancel('用戶取消了請(qǐng)求'); // 傳入一個(gè)可選的消息
console.log('請(qǐng)求已嘗試取消');
}, 100); // 100ms 后取消請(qǐng)求
優(yōu)點(diǎn):
在舊版本 Axios 中廣泛使用。
缺點(diǎn):
- Axios 特有的 API,不適用于其他 Web API。
- 已被
AbortController替代,未來(lái)可能不再維護(hù)或推薦。
何時(shí)需要取消請(qǐng)求
取消請(qǐng)求在前端開(kāi)發(fā)中非常有用,常見(jiàn)場(chǎng)景包括:
- 組件卸載時(shí):當(dāng)用戶在請(qǐng)求完成前切換頁(yè)面或組件被銷(xiāo)毀時(shí),避免因請(qǐng)求返回后嘗試更新已不存在的組件狀態(tài)而導(dǎo)致的內(nèi)存泄漏或錯(cuò)誤。
- 用戶操作取消:例如,用戶點(diǎn)擊了“取消上傳”按鈕,或在搜索框中快速輸入時(shí),取消之前的舊搜索請(qǐng)求,只保留最新的請(qǐng)求。
- 避免重復(fù)請(qǐng)求:在某些情況下,為了防止用戶多次點(diǎn)擊或快速觸發(fā)某個(gè)操作導(dǎo)致發(fā)送多個(gè)相同的請(qǐng)求,可以在新請(qǐng)求發(fā)出前取消舊請(qǐng)求。
總之,Axios 提供了強(qiáng)大且靈活的請(qǐng)求取消機(jī)制,推薦在現(xiàn)代項(xiàng)目中使用 AbortController。
這種取消是前端拒絕接收數(shù)據(jù)還是真的停止http的請(qǐng)求鏈接呢?
1. 它是如何“真取消”的?(瀏覽器層面)
當(dāng)你調(diào)用 controller.abort()(或舊版的 cancelToken)時(shí),Axios 會(huì)調(diào)用瀏覽器底層的 API(XMLHttpRequest.abort() 或 fetch 的 signal 機(jī)制)。
這意味著:
- 網(wǎng)絡(luò)連接被切斷:瀏覽器會(huì)立即關(guān)閉與服務(wù)器的 TCP 連接。
- 停止接收數(shù)據(jù):如果服務(wù)器正在發(fā)送一個(gè)很大的響應(yīng)(比如下載一個(gè) 100MB 的文件),瀏覽器會(huì)立刻停止下載,節(jié)省帶寬。
- Promise 立即 Reject:Axios 的 Promise 會(huì)立刻拋出一個(gè)
CanceledError,你的代碼會(huì)立刻進(jìn)入.catch(),而不需要等待服務(wù)器響應(yīng)超時(shí)。
對(duì)比: 如果僅僅是“前端不予接收”,瀏覽器會(huì)傻傻地把 100MB 下載完,然后你的代碼再把數(shù)據(jù)扔掉。Axios 的取消是前者,直接掐斷連接,節(jié)省資源。
2. 服務(wù)器端發(fā)生了什么?(后端層面)
這是最容易產(chǎn)生誤解的地方。 “前端取消了請(qǐng)求”并不代表“后端撤銷(xiāo)了操作”。
請(qǐng)求已發(fā)出:在大多數(shù)情況下,當(dāng)你點(diǎn)擊取消時(shí),請(qǐng)求指令已經(jīng)通過(guò)網(wǎng)絡(luò)發(fā)送到了服務(wù)器。
服務(wù)器正在處理:服務(wù)器收到請(qǐng)求后,開(kāi)始查詢數(shù)據(jù)庫(kù)、計(jì)算數(shù)據(jù)或?qū)懭胗涗洝?/p>
連接中斷:此時(shí)前端斷開(kāi)了連接。
- 大多數(shù)后端框架(如 Java Spring, Node Express, Python Flask) :通常不會(huì)自動(dòng)檢測(cè)連接斷開(kāi)而停止業(yè)務(wù)邏輯。它們會(huì)繼續(xù)把活干完(比如把數(shù)據(jù)寫(xiě)進(jìn)數(shù)據(jù)庫(kù)),然后試圖把結(jié)果返回給前端。
- 結(jié)果:當(dāng)服務(wù)器試圖返回結(jié)果時(shí),發(fā)現(xiàn)連接已經(jīng)沒(méi)了,服務(wù)器會(huì)報(bào)錯(cuò)(如
Broken pipe),但之前的業(yè)務(wù)邏輯(如寫(xiě)庫(kù))可能已經(jīng)執(zhí)行了。
舉個(gè)例子:
你在餐廳點(diǎn)了一道菜(發(fā)送請(qǐng)求)。
廚師開(kāi)始做菜(服務(wù)器處理)。
你突然有急事走了,跟服務(wù)員說(shuō)“我不要了”(前端取消請(qǐng)求)。
- 前端視角:你走了,沒(méi)吃到菜,也沒(méi)付錢(qián)(節(jié)省了時(shí)間和資源)。
- 后端視角:廚師可能已經(jīng)把菜做好了,發(fā)現(xiàn)沒(méi)人吃,只能倒掉。但菜確實(shí)被做出來(lái)了(副作用已產(chǎn)生)。
3. 總結(jié):三種情況
根據(jù)取消的時(shí)機(jī)不同,效果也不同:
請(qǐng)求還在排隊(duì)(極少見(jiàn)) :
- 瀏覽器還沒(méi)來(lái)得及把請(qǐng)求發(fā)出去你就取消了。
- 結(jié)果:服務(wù)器完全不知道有這回事,這是最徹底的取消。
請(qǐng)求在傳輸中/服務(wù)器處理中(最常見(jiàn)) :
- 請(qǐng)求已發(fā),服務(wù)器正在算,前端取消。
- 結(jié)果:前端斷開(kāi)連接,不再等待。服務(wù)器可能還是會(huì)把活干完,但發(fā)不回來(lái)。這對(duì)前端來(lái)說(shuō)是真取消(不卡界面、不費(fèi)流量),對(duì)后端來(lái)說(shuō)通常無(wú)法撤銷(xiāo)副作用。
響應(yīng)已到達(dá)瀏覽器:
- 服務(wù)器數(shù)據(jù)已經(jīng)發(fā)回來(lái)了,瀏覽器剛收到,你正好點(diǎn)了取消。
- 結(jié)果:這時(shí)候其實(shí)已經(jīng)晚了,Axios 只是拋個(gè)錯(cuò)讓你忽略結(jié)果。這就變成了你說(shuō)的“前端不予接收”。
核心建議
用于優(yōu)化體驗(yàn):Axios 的取消非常適合用于搜索框聯(lián)想(輸入 a 發(fā)請(qǐng)求,緊接著輸入 ab,此時(shí)取消 a 的請(qǐng)求)或切換 Tab。這能有效防止“舊數(shù)據(jù)的響應(yīng)覆蓋了新數(shù)據(jù)”的 Bug,并節(jié)省帶寬。
不要依賴(lài)它來(lái)回滾數(shù)據(jù):如果你發(fā)的是 POST 請(qǐng)求(比如“付款”),千萬(wàn)不要指望前端取消就能阻止服務(wù)器扣款。后端必須要有冪等性設(shè)計(jì)或?qū)iT(mén)的撤銷(xiāo)接口。
到此這篇關(guān)于一文深入詳解Axios請(qǐng)求取消機(jī)制的文章就介紹到這了,更多相關(guān)Axios請(qǐng)求取消機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于el-slider實(shí)現(xiàn)一個(gè)能拖動(dòng)的時(shí)間范圍選擇器
這篇文章主要介紹了基于el-slider實(shí)現(xiàn)一個(gè)能拖動(dòng)的時(shí)間范圍選擇器,并通過(guò)實(shí)例代碼介紹了基于element-ui el-slider實(shí)現(xiàn)滑動(dòng)限位器的方法,需要的朋友可以參考下2024-02-02
Echarts地圖添加引導(dǎo)線效果(labelLine)
這篇文章主要介紹了Echarts地圖添加引導(dǎo)線效果(labelLine),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
Bootstrap實(shí)現(xiàn)響應(yīng)式導(dǎo)航欄效果
這篇文章主要介紹了Bootstrap實(shí)現(xiàn)響應(yīng)式導(dǎo)航欄效果,導(dǎo)航欄是一個(gè)很好的功能,是Bootstrap網(wǎng)站的一個(gè)突出特點(diǎn),本文帶領(lǐng)大家學(xué)習(xí)實(shí)現(xiàn)Bootstrap導(dǎo)航欄,需要的朋友可以參考下2015-12-12
如何在指定的地方插入html內(nèi)容和文本內(nèi)容
本文為大家介紹個(gè)小技巧可以在指定的地方插入html內(nèi)容和文本內(nèi)容,示例如下,感興趣的朋友可以參考下2013-12-12
JS設(shè)計(jì)模式之狀態(tài)模式概念與用法分析
這篇文章主要介紹了JS設(shè)計(jì)模式之狀態(tài)模式概念與用法,簡(jiǎn)單講述了狀態(tài)模式的概念、功能、應(yīng)用場(chǎng)景并結(jié)合javascript實(shí)例形式分析了狀態(tài)模式的簡(jiǎn)單定義及使用方法,需要的朋友可以參考下2018-02-02
JS產(chǎn)生隨機(jī)數(shù)的用法小結(jié)
本文給大家分享js產(chǎn)生隨機(jī)數(shù)的用法小結(jié),非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起看看吧2016-12-12

