最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

在Vue3項目中取消重復請求的兩種方案

 更新時間:2026年02月07日 09:58:42   作者:用戶3905133219288  
文章主要介紹了在Vue3項目中如何取消重復請求,以節(jié)省資源、保證數(shù)據(jù)正確性和提升用戶體驗,文章詳細講解了兩種實現(xiàn)方式:使用Axios的CancelToken和AbortController,需要的朋友可以參考下

今天我們來聊聊一個實際開發(fā)中常見的問題:在Vue3項目中,如何取消重復的請求。

為什么需要取消重復請求?

這樣做有幾個明顯的好處:

  1.  節(jié)省資源:釋放瀏覽器連接,減輕服務器壓力。
  2.  保證數(shù)據(jù)正確性:避免因請求響應順序錯亂導致頁面顯示舊數(shù)據(jù)。
  3.  提升用戶體驗:防止無效請求阻塞后續(xù)有效操作。

在Vue3的生態(tài)中,我們最常用的HTTP客戶端是 axios。因此,本文的核心將圍繞如何使用 axios 的取消令牌(CancelToken)及其更現(xiàn)代的替代品——AbortController——來實現(xiàn)請求取消。

方案一:使用 Axios 的 CancelToken

axios 從很早就支持通過 CancelToken 來取消請求。雖然它在 axios v0.22.0 之后被標記為已棄用,轉(zhuǎn)而推薦使用標準的 AbortController,但很多現(xiàn)有項目仍在使用這個API,所以我們有必要了解一下。 它的工作原理是:創(chuàng)建一個“取消令牌”的源(source),將這個令牌配置到請求中。當我們需要取消請求時,調(diào)用這個源的 cancel 方法。

基本使用示例

import?axios?from?'axios';

// 1. 創(chuàng)建一個 CancelToken Source
const?source = axios.CancelToken.source();

// 2. 發(fā)起請求,并配置 cancelToken
axios.get('/api/user/123', {
? cancelToken: source.token
}).then(response?=>?{
? console.log(response.data);
}).catch(function?(thrown) {
? // 判斷錯誤是否是因為請求被取消
? if?(axios.isCancel(thrown)) {
? ? console.log('請求被取消:', thrown.message);
? }?else?{
? ? // 處理其他錯誤
? }
});

// 3. 在需要的時候取消請求
source.cancel('操作被用戶取消');

在Vue3組件中管理重復請求

在實際項目中,我們通常需要一種機制來管理“同一個”重復請求。一個常見的思路是:將每個請求的唯一標識(例如:請求方法+URL)和一個取消函數(shù)關(guān)聯(lián)起來,在發(fā)起新請求前,檢查并取消舊的、未完成的相同請求。

我們可以利用Vue3的響應式系統(tǒng)和組合式API,封裝一個可復用的邏輯。

首先,我們創(chuàng)建一個用于存儲所有進行中請求的Map,以及相關(guān)的操作函數(shù)。

// utils/request.js
import?axios?from?'axios';

// 存儲所有進行中請求的Map
const?pendingRequestMap =?new?Map();

/**
?* 生成請求的唯一標識鍵
?*?@param?{*} config axios的請求配置對象
?*?@returns?{string} 唯一鍵
?*/
function?generateReqKey(config) {
? const?{ method, url, params, data } = config;
? // 簡單拼接,可根據(jù)業(yè)務復雜化(如對data排序)
? return?[method, url,?JSON.stringify(params),?JSON.stringify(data)].join('&');
}

/**
?* 添加請求到等待隊列
?*?@param?{*} config axios的請求配置對象
?*/
function?addPendingRequest(config) {
? const?requestKey =?generateReqKey(config);
? // 為這個請求創(chuàng)建一個取消令牌源
? config.cancelToken?= config.cancelToken?||?new?axios.CancelToken((cancel) =>?{
? ? // 如果Map中還沒有這個key,則添加進去
? ? if?(!pendingRequestMap.has(requestKey)) {
? ? ? pendingRequestMap.set(requestKey, cancel);
? ? }
? });
}

/**
?* 移除等待隊列中的請求
?*?@param?{*} config axios的請求配置對象
?*/
function?removePendingRequest(config) {
? const?requestKey =?generateReqKey(config);
? if?(pendingRequestMap.has(requestKey)) {
? ? // 如果在Map中存在這個請求,說明它還未完成,將其取消并從Map中移除
? ? const?cancel = pendingRequestMap.get(requestKey);
? ? cancel(requestKey);?// 取消請求,可以傳遞消息
? ? pendingRequestMap.delete(requestKey);
? }
}

// 創(chuàng)建axios實例
const?service = axios.create({
? timeout:?10000,
});

// 請求攔截器:在請求發(fā)出前,檢查并取消重復請求
service.interceptors.request.use(
? (config) =>?{
? ? // 檢查并取消之前的相同請求
? ? removePendingRequest(config);
? ? // 將當前請求添加到等待隊列
? ? addPendingRequest(config);
? ? return?config;
? },
? (error) =>?{
? ? return?Promise.reject(error);
? }
);

// 響應攔截器:請求完成后(無論成功失?。瑢⑵鋸牡却犃兄幸瞥?
service.interceptors.response.use(
? (response) =>?{
? ? removePendingRequest(response.config);
? ? return?response;
? },
? (error) =>?{
? ? // 如果錯誤是因為取消請求造成的,我們選擇忽略這個錯誤,不拋出到業(yè)務層
? ? if?(axios.isCancel(error)) {
? ? ? console.log('已取消的重復請求:', error.message);
? ? ? return?new?Promise(() =>?{});?// 返回一個“永遠pending”的Promise,中斷Promise鏈
? ? }
? ? // 對于其他錯誤,移除請求并正常拋出
? ? removePendingRequest(error.config?|| {});
? ? return?Promise.reject(error);
? }
);

export?default?service;

然后,在Vue組件中,你可以直接使用這個封裝好的 service 來發(fā)起請求。它會自動處理重復請求的取消。

<script setup>
import?{ ref }?from?'vue';
import?request?from?'@/utils/request';

const?searchResults =?ref([]);
const?loading =?ref(false);

const?handleSearch?=?async?(keyword) => {
? loading.value?=?true;
? try?{
? ? const?response =?await?request.get('/api/search', {
? ? ? params: { keyword }
? ? });
? ? searchResults.value?= response.data;
? }?catch?(error) {
? ? // 這里不會捕獲到因重復請求被取消而拋出的錯誤,因為我們在攔截器中已經(jīng)處理了
? ? console.error('搜索失敗:', error);
? }?finally?{
? ? loading.value?=?false;
? }
};
</script>

注意:CancelToken 方式在 axios 新版本中已被標記為棄用。對于新項目,建議直接使用下面介紹的更現(xiàn)代的 AbortController 方案。

方案二: AbortController

AbortController 是一個現(xiàn)代的Web API,它提供了一種更通用、更標準的方式來中止一個或多個Web請求。fetch API 和新的 axios 版本都原生支持它。使用 AbortController 是當前推薦的做法。

基本概念

  • AbortController:控制器對象,用于觸發(fā)中止信號。
  • AbortSignal:信號對象,關(guān)聯(lián)到具體的請求上??刂破骺梢酝ㄟ^它來通知請求“需要中止”。

基本使用示例

// 1. 創(chuàng)建一個 AbortController 實例
const?controller =?new?AbortController();
const?signal = controller.signal;?// 獲取它的 signal

// 2. 發(fā)起 fetch 請求,并將 signal 關(guān)聯(lián)上去
fetch('/api/some-data', { signal })
? .then(response?=>?response.json())
? .then(data?=>?console.log(data))
? .catch(err?=>?{
? ? // 如果錯誤是因為請求被中止
? ? if?(err.name?===?'AbortError') {
? ? ? console.log('Fetch 請求被中止');
? ? }?else?{
? ? ? console.error('其他錯誤:', err);
? ? }
? });

// 3. 在需要的時候中止請求
controller.abort();?// 這會觸發(fā) signal 的中止事件,從而取消請求

在 Axios 中使用 AbortController

從 axios v0.22.0 開始,你可以使用 signal 屬性來配置 AbortSignal。

import?axios?from?'axios';

const?controller =?new?AbortController();

axios.get('/api/user/123', {
? signal: controller.signal?// 將 signal 傳遞給請求配置
}).then(response?=>?{
? console.log(response.data);
}).catch(function?(error) {
? // 判斷錯誤是否是因為請求被取消
? if?(axios.isCancel(error)) {
? ? console.log('請求被取消:', error.message);
? }?else?{
? ? // 處理其他錯誤
? }
});

// 取消請求
controller.abort();

封裝基于 AbortController 的重復請求取消

我們可以用類似的思路,用 AbortController 重構(gòu)之前的工具函數(shù)。主要變化是將存儲的 cancel 函數(shù)替換為 AbortController 實例。

// utils/request-abort.js
import?axios?from?'axios';

const?pendingRequestMap =?new?Map();

function?generateReqKey(config) {
? const?{ method, url, params, data } = config;
? return?[method, url,?JSON.stringify(params),?JSON.stringify(data)].join('&');
}

function?addPendingRequest(config) {
? const?requestKey =?generateReqKey(config);
? // 如果已有相同請求在進行,則中止它
? if?(pendingRequestMap.has(requestKey)) {
? ? const?oldController = pendingRequestMap.get(requestKey);
? ? oldController.abort();?// 中止舊的請求
? ? pendingRequestMap.delete(requestKey);
? }
? // 為當前請求創(chuàng)建新的控制器并存儲
? const?controller =?new?AbortController();
? config.signal?= controller.signal;?// 關(guān)鍵:將 signal 賦給請求配置
? pendingRequestMap.set(requestKey, controller);
}

function?removePendingRequest(config) {
? const?requestKey =?generateReqKey(config);
? if?(pendingRequestMap.has(requestKey)) {
? ? // 請求完成,直接從Map中移除即可,不需要手動abort
? ? pendingRequestMap.delete(requestKey);
? }
}

const?service = axios.create({
? timeout:?10000,
});

service.interceptors.request.use(
? (config) =>?{
? ? removePendingRequest(config);?// 先移除可能存在的舊記錄(清理作用)
? ? addPendingRequest(config);?// 添加新請求
? ? return?config;
? },
? (error) =>?{
? ? return?Promise.reject(error);
? }
);

service.interceptors.response.use(
? (response) =>?{
? ? removePendingRequest(response.config);
? ? return?response;
? },
? (error) =>?{
? ? // 判斷錯誤是否由取消請求導致
? ? if?(axios.isCancel(error)) {
? ? ? console.log('已取消的重復請求:', error.message);
? ? ? return?new?Promise(() =>?{});?// 中斷Promise鏈
? ? }
? ? removePendingRequest(error.config?|| {});
? ? return?Promise.reject(error);
? }
);

export?default?service;

這個版本的邏輯更清晰:在添加新請求時,直接中止舊的相同請求。響應攔截器里只需要做清理工作。

進階與優(yōu)化

上面的方案解決了核心問題,但在實際項目中,我們可能還需要考慮更多細節(jié)。

1. 白名單控制

有些請求我們可能不希望被自動取消。例如,一個輪詢定時請求,或者多個并行的不同數(shù)據(jù)請求。我們可以通過給請求配置添加一個自定義標記(如 allowRepeat: true)來實現(xiàn)白名單。

// 在攔截器中
service.interceptors.request.use(
? (config) =>?{
? ? // 如果配置了允許重復,則跳過取消邏輯
? ? if?(config.allowRepeat) {
? ? ? return?config;
? ? }
? ? removePendingRequest(config);
? ? addPendingRequest(config);
? ? return?config;
? }
);

// 在組件中使用
request.get('/api/polling', {?allowRepeat:?true?});

2. 與 Vue Router 導航守衛(wèi)結(jié)合

當用戶切換頁面時,我們通常希望取消所有未完成的請求,以免它們在后臺繼續(xù)運行并可能更新一個已經(jīng)銷毀的組件狀態(tài)。這可以在Vue Router的全局前置守衛(wèi)中實現(xiàn)。

// router/index.js
import?router?from?'./router';
import?{ pendingRequestMap }?from?'@/utils/request-abort';?// 需要將map導出

router.beforeEach((to,?from, next) =>?{
? // 遍歷并中止所有進行中的請求
? pendingRequestMap.forEach((controller, key) =>?{
? ? controller.abort(`路由跳轉(zhuǎn)至?${to.path}`);
? });
? // 清空Map
? pendingRequestMap.clear();
? next();
});

3. 使用 Composition API 封裝

在Vue3中,我們可以利用組合式API,將取消邏輯封裝成一個更優(yōu)雅、可復用的 useRequest Hook。

// composables/useRequest.js
import?{ ref, onUnmounted }?from?'vue';
import?request?from?'@/utils/request-abort';

export?function?useRequest() {
? const?data =?ref(null);
? const?error =?ref(null);
? const?loading =?ref(false);
? let?abortController =?null;

? const?execute?=?async?(config) => {
? ? loading.value?=?true;
? ? error.value?=?null;
? ? // 為這次執(zhí)行創(chuàng)建一個獨立的控制器(可選,如果全局已管理則可省略)
? ? abortController =?new?AbortController();
? ? try?{
? ? ? const?response =?await?request({
? ? ? ? ...config,
? ? ? ? signal: abortController.signal
? ? ? });
? ? ? data.value?= response.data;
? ? ? return?response;
? ? }?catch?(err) {
? ? ? if?(!axios.isCancel(err)) {
? ? ? ? error.value?= err;
? ? ? }
? ? ? throw?err;
? ? }?finally?{
? ? ? loading.value?=?false;
? ? }
? };

? // 組件卸載時,取消由這個Hook發(fā)起的請求
? onUnmounted(() =>?{
? ? if?(abortController) {
? ? ? abortController.abort();
? ? }
? });

? // 提供一個手動取消的方法
? const?cancel?= () => {
? ? if?(abortController) {
? ? ? abortController.abort();
? ? }
? };

? return?{
? ? data,
? ? error,
? ? loading,
? ? execute,
? ? cancel
? };
}

在組件中使用:

<script setup>
import?{ useRequest }?from?'@/composables/useRequest';

const?{ data, loading, execute } =?useRequest();

const?handleSubmit?= () => {
? execute({
? ? method:?'post',
? ? url:?'/api/submit',
? ? data: {?/* ... */?}
? });
};
</script>

取消重復請求是一個看似簡單,但能顯著提升應用健壯性的優(yōu)化點。在Vue3項目中,結(jié)合 axios 和 AbortController,我們可以用清晰的代碼實現(xiàn)這一功能。希望本文介紹的方法和思路,能幫助你更好地處理項目中的網(wǎng)絡(luò)請求問題。

以上就是在Vue3項目中取消重復請求的兩種方案的詳細內(nèi)容,更多關(guān)于Vue3取消重復請求方案的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Vue自定義表單內(nèi)容檢查rules實例

    Vue自定義表單內(nèi)容檢查rules實例

    這篇文章主要介紹了Vue自定義表單內(nèi)容檢查rules實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • 如何封裝了一個vue移動端下拉加載下一頁數(shù)據(jù)的組件

    如何封裝了一個vue移動端下拉加載下一頁數(shù)據(jù)的組件

    這篇文章主要介紹了如何封裝了一個vue移動端下拉加載下一頁數(shù)據(jù)的組件,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • Vue項目中使用addRoutes出現(xiàn)問題的解決方法

    Vue項目中使用addRoutes出現(xiàn)問題的解決方法

    大家應該都知道可以通過vue-router官方提供的一個api-->addRoutes可以實現(xiàn)路由添加的功能,事實上就也就實現(xiàn)了用戶權(quán)限,這篇文章主要給大家介紹了關(guān)于Vue項目中使用addRoutes出現(xiàn)問題的解決方法,需要的朋友可以參考下
    2021-08-08
  • 用Vue寫一個分頁器的示例代碼

    用Vue寫一個分頁器的示例代碼

    本篇文章主要介紹了用Vue寫一個分頁器的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • Vue腳手架配置代理服務器的兩種方式(小結(jié))

    Vue腳手架配置代理服務器的兩種方式(小結(jié))

    本文主要介紹了Vue腳手架配置代理服務器的兩種方式(小結(jié)),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-01-01
  • 詳解Vue用自定義指令完成一個下拉菜單(select組件)

    詳解Vue用自定義指令完成一個下拉菜單(select組件)

    本篇文章主要介紹了詳解Vue用自定義指令完成一個下拉菜單(select組件),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • vue項目搭建以及全家桶的使用詳細教程(小結(jié))

    vue項目搭建以及全家桶的使用詳細教程(小結(jié))

    這篇文章主要介紹了vue項目搭建以及全家桶的使用詳細教程(小結(jié)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12
  • 深入了解Vue3中props的原理與使用

    深入了解Vue3中props的原理與使用

    props指父組件往子組件中傳入?yún)?shù),這篇文章主要為大家介紹了vue3中props的原理與使用,文中的示例代碼講解詳細,感興趣的可以了解一下
    2023-05-05
  • vue3動態(tài)加載對話框的方法實例

    vue3動態(tài)加載對話框的方法實例

    對話框是很常用的組件,在很多地方都會用到,下面這篇文章主要給大家介紹了關(guān)于vue3動態(tài)加載對話框的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-03-03
  • 詳解vue3?defineModel如何實現(xiàn)雙向綁定

    詳解vue3?defineModel如何實現(xiàn)雙向綁定

    隨著?Vue?3.3?引入的?defineModel?宏,開發(fā)者可以更加簡潔地實現(xiàn)組件內(nèi)部的雙向數(shù)據(jù)綁定,下面就跟隨小編一起來學習一下如何使用defineModel實現(xiàn)雙向綁定吧
    2024-12-12

最新評論

惠东县| 长乐市| 扎囊县| 武夷山市| 高碑店市| 遂昌县| 阳江市| 壶关县| 奈曼旗| 博兴县| 全南县| 琼结县| 米易县| 丽水市| 甘南县| 银川市| 朝阳县| 定西市| 嵩明县| 筠连县| 衢州市| 宜兰市| 梁河县| 金坛市| 广宗县| 龙胜| 汉寿县| 平度市| 大宁县| 炉霍县| 沈阳市| 新化县| 灵武市| 通榆县| 湾仔区| 宝山区| 金昌市| 江山市| 黄梅县| 黄大仙区| 溧阳市|