使用場(chǎng)景
在前端開發(fā)中,我們經(jīng)常需要中斷請(qǐng)求來優(yōu)化性能或處理特定的業(yè)務(wù)需求。以下是一些常見的使用場(chǎng)景:
比如
- 重復(fù)請(qǐng)求:當(dāng)頁面中多個(gè)組件并發(fā)調(diào)用同一個(gè)接口時(shí),在第一個(gè)請(qǐng)求返回后,我們可能需要中斷其他組件對(duì)該接口的調(diào)用,以避免重復(fù)請(qǐng)求和冗余數(shù)據(jù)。這在組件高度復(fù)用、不依賴公共 API 的情況下特別有用。
- 競(jìng)態(tài)請(qǐng)求:當(dāng)頁面定時(shí)輪詢發(fā)起請(qǐng)求時(shí),如果上一個(gè)請(qǐng)求的響應(yīng)速度比下一個(gè)請(qǐng)求慢,會(huì)導(dǎo)致數(shù)據(jù)錯(cuò)亂。中斷較慢的請(qǐng)求可以確保只處理最新的數(shù)據(jù),避免競(jìng)態(tài)條件。
- 無效請(qǐng)求:在單頁應(yīng)用中,當(dāng)組件加載過慢,路由跳轉(zhuǎn)后可能會(huì)導(dǎo)致組件卸載,但請(qǐng)求仍在進(jìn)行中。如果接口返回錯(cuò)誤,錯(cuò)誤提示可能會(huì)在其他頁面彈出。中斷無效請(qǐng)求可以避免不必要的錯(cuò)誤提示。
- 大文件上傳暫停與恢復(fù):在實(shí)現(xiàn)大文件上傳功能時(shí),用戶可能會(huì)需要暫停和恢復(fù)上傳過程。中斷請(qǐng)求可以實(shí)現(xiàn)暫停功能,并在需要時(shí)重新發(fā)起請(qǐng)求以實(shí)現(xiàn)恢復(fù)上傳。
除了以上提到的場(chǎng)景,還有許多其他情況需要中斷請(qǐng)求以減少對(duì)服務(wù)器的無效請(qǐng)求。
下面介紹幾種終止請(qǐng)求的方案
原生ajax終止請(qǐng)求
abort() 方法
XMLHttpRequest.abort() 方法用于終止 XMLHttpRequest 對(duì)象的請(qǐng)求。調(diào)用該方法后,如果請(qǐng)求正在處理中,則會(huì)中止該請(qǐng)求;如果請(qǐng)求已經(jīng)完成(即已經(jīng)接收到完整的響應(yīng)),則不會(huì)執(zhí)行任何操作。同時(shí),調(diào)用該方法會(huì)觸發(fā) XMLHttpRequest 對(duì)象的 abort 事件,我們可以在事件處理函數(shù)中執(zhí)行后續(xù)的邏輯代碼,如清除請(qǐng)求相關(guān)的數(shù)據(jù)等。
當(dāng)一個(gè)請(qǐng)求被終止后,它的 readyState 屬性將變?yōu)?0,status 屬性也會(huì)變?yōu)?0。
案例代碼:
// 創(chuàng)建XMLHttpRequest對(duì)象
const xhr = new XMLHttpRequest();
// 請(qǐng)求地址
const url = "https://developer.mozilla.org/";
// 初始化請(qǐng)求
xhr.open('GET', url, true);
// 發(fā)送請(qǐng)求
xhr.send();
// 監(jiān)聽取消請(qǐng)求
xhr.addEventListener('abort', function () {
console.log('請(qǐng)求被abort()取消了');
});
// 定時(shí)器模擬取消請(qǐng)求
setTimeout(() => {
// 取消請(qǐng)求
xhr.abort();
// 取消請(qǐng)求之后的狀態(tài)status
console.log('abort()之后的xhr.status---', xhr.status);
// 取消請(qǐng)求之后的狀態(tài)readyState
console.log('abort()之后的xhr.readyState---', xhr.readyState);
}, 100);
fetch 終止請(qǐng)求
使用 AbortController 可以中斷 Fetch 請(qǐng)求。AbortController 是一個(gè)新的 Web 標(biāo)準(zhǔn),用于中止 DOM 請(qǐng)求和 Fetch 請(qǐng)求。在執(zhí)行 Fetch 請(qǐng)求時(shí),可以通過 AbortController 創(chuàng)建一個(gè)信號(hào)對(duì)象 signal,并將 signal 作為配置選項(xiàng)傳遞給 fetch() 方法,這樣就可以通過調(diào)用 AbortController 對(duì)象的 abort() 方法來中止請(qǐng)求。
案例代碼:
const controller = new AbortController();
const { signal } = controller;
// 請(qǐng)求地址
const url = "https://developer.mozilla.org/";
fetch(url, { signal })
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
// 中止 fetch 請(qǐng)求
controller.abort();
axios 終止請(qǐng)求
AbortController(新版本)
從 axios 的 0.22.0 版本開始,推薦使用瀏覽器原生的 AbortController 來終止請(qǐng)求。當(dāng)使用該方法終止請(qǐng)求時(shí),如果請(qǐng)求正在處理中,則會(huì)中止該請(qǐng)求;如果請(qǐng)求已經(jīng)完成(即已經(jīng)接收到完整的響應(yīng)),則不會(huì)執(zhí)行任何操作。
我們可以通過兩種方式來監(jiān)聽終止請(qǐng)求的操作并進(jìn)行后續(xù)處理:
- 使用 AbortController 提供的 onabort 事件,通過監(jiān)聽該事件并綁定事件處理函數(shù),在函數(shù)中執(zhí)行后續(xù)處理邏輯。
- 使用 try…catch,終止請(qǐng)求后會(huì)觸發(fā) catch,可以在 catch 中進(jìn)行后續(xù)處理。如果同時(shí)使用 onabort 事件和 try…catch,則會(huì)先觸發(fā) onabort 事件,再觸發(fā) try…catch。
案例代碼:
// 以vue項(xiàng)目中使用axios為例
// 創(chuàng)建請(qǐng)求控制器
this.controller = new AbortController();
console.log("初始聲明的請(qǐng)求控制器------", this.controller);
const url = "https://developer.mozilla.org/";
// 第一種方法:綁定事件處理程序
this.controller.signal.addEventListener("abort", () => {
console.log("請(qǐng)求已終止,觸發(fā)了onabort事件");
// 進(jìn)行后續(xù)處理
});
// 第二種方法:try...catch
try {
// 發(fā)送文件上傳請(qǐng)求
const res = await this.$axios.post(url, {}, {
timeout: 0, // 設(shè)置超時(shí)時(shí)間為 0/null 表示永不超時(shí)
signal: this.controller.signal, // 綁定取消請(qǐng)求的信號(hào)量
});
} catch (error) {
console.log("終止請(qǐng)求時(shí)catch的error---", error);
// 判斷是否為取消上傳
if (error.message == "canceled"){
// 進(jìn)行后續(xù)處理
};
}
// 終止請(qǐng)求
this.controller.abort();
console.log("終止請(qǐng)求后的請(qǐng)求控制器------", this.controller);
需要注意的是,每個(gè) AbortController 可以同時(shí)取消多個(gè)請(qǐng)求,但只能取消請(qǐng)求一次。終止請(qǐng)求后,該請(qǐng)求的 signal.aborted 屬性會(huì)從 false 變?yōu)?true。目前,暫無方法可以將其恢復(fù)為 false。如果后續(xù)請(qǐng)求仍然綁定了該請(qǐng)求控制器,那么后續(xù)請(qǐng)求都會(huì)被提前終止,不會(huì)被發(fā)送。
如果想要在終止請(qǐng)求后不影響后續(xù)請(qǐng)求的正常發(fā)送,并且后續(xù)請(qǐng)求也能夠被終止,需要在每次發(fā)送請(qǐng)求之前都通過構(gòu)造函數(shù)創(chuàng)建一個(gè)新的 AbortController,并將每次請(qǐng)求綁定到新的 AbortController 上,以確保多次請(qǐng)求之間不會(huì)相互干擾。
CancelToken( axios 舊版本)
在 axios 的 0.22.0 版本之前,可以使用取消令牌(CancelToken)來中止請(qǐng)求。不過,從 0.22.0 版本開始,該 API 已被棄用,不再建議使用。當(dāng)使用該方法終止請(qǐng)求時(shí),如果請(qǐng)求正在處理中,則會(huì)中止該請(qǐng)求;如果請(qǐng)求已經(jīng)完成(即已經(jīng)接收到完整的響應(yīng)),則不會(huì)執(zhí)行任何操作。
該方法只能通過try…catch來監(jiān)聽取消請(qǐng)求操作,終止請(qǐng)求之后,會(huì)觸發(fā)catch,在catch中進(jìn)行后續(xù)處理。而且該方法在取消請(qǐng)求時(shí),可以通過參數(shù)自定義catch的error中的message內(nèi)容。
案例代碼:
// 以vue項(xiàng)目中使用axios為例
// 這個(gè)地方需要導(dǎo)入原生的axios 最好不要使用二次封裝后的axios
import axios from "axios";
const url = "https://developer.mozilla.org/";
// 創(chuàng)建請(qǐng)求令牌
this.source = axios.CancelToken.source();
console.log("初始聲明的請(qǐng)求令牌---", this.source);
// 第二種方法:try...catch
try {
// 發(fā)送文件上傳請(qǐng)求
const res = await this.$axios.post(url, {}, {
timeout: 0, // 設(shè)置超時(shí)時(shí)間為 0/null 表示永不超時(shí)
cancelToken: this.source.token, // 綁定取消請(qǐng)求的令牌
});
} catch (error) {
console.log("終止請(qǐng)求時(shí)catch的error---", error);
// 判斷是否為取消上傳
if (error.message == "自定義取消請(qǐng)求的message"){
// 進(jìn)行后續(xù)處理
};
}
// 終止請(qǐng)求
this.source.cancel("自定義取消請(qǐng)求的message");
console.log("取消請(qǐng)求后的請(qǐng)求令牌---", this.source);
注意:該方法與AbortController相同,都可以同時(shí)取消多個(gè)請(qǐng)求,但是只能取消請(qǐng)求一次,一個(gè)CancelToken在終止過請(qǐng)求之后,如果后續(xù)請(qǐng)求還是綁定該請(qǐng)求令牌,則后續(xù)請(qǐng)求都會(huì)被提前終止,不會(huì)被發(fā)出。文章來源:http://www.zghlxwxcb.cn/news/detail-758307.html
同理,如果我們想要在終止請(qǐng)求之后,不影響后續(xù)請(qǐng)求的正常發(fā)出,且后續(xù)請(qǐng)求也是可以被終止的,那么需要在每次發(fā)出請(qǐng)求之前,都創(chuàng)建一個(gè)新的的 CancelToken,每次請(qǐng)求綁定的都是新的CancelToken,這樣才能做到多次請(qǐng)求之間不干擾。文章來源地址http://www.zghlxwxcb.cn/news/detail-758307.html
到了這里,關(guān)于前端如何中斷請(qǐng)求 ( axios、原生 ajax、fetch)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!