Vue?Axios請求取消和重發(fā)封裝的實現(xiàn)代碼
場景
如圖,有時候請求后端同一接口時,會因接口響應速度過慢,導致前端原本頁面應顯示a,結果顯示b。像上圖,前端頁面看起來就是先顯示 請求b 的數(shù)據(jù),然后是 請求c 的數(shù)據(jù),最后是 請求a 的數(shù)據(jù),但是實際上我們只需要顯示最后的 請求c 的數(shù)據(jù)。而且這樣還會導致頁面渲染出現(xiàn)閃爍。
需求
- 實現(xiàn)取消重復請求(有多種取消方式)
- 發(fā)出第一個請求,取消后面的相同請求
- 取消前面的請求,只發(fā)出最后一個請求
- 實現(xiàn)請求失敗后,自動重發(fā)指定次數(shù)
實現(xiàn)1(發(fā)出第一個請求,取消后面的相同請求)
import Axios from "axios"; // 創(chuàng)建一個實例 const service = Axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 1000, }); // 添加請求攔截器 service.interceptors.request.use( (config) => { // 判斷是否有 token if (getToken()) { config.headers["Permission-Token"] = getToken(); } // 添加待處理請求 addPendingRequest(config); return config; }, (error) => { return Promise.reject(error); } ); // 添加響應攔截器 service.interceptors.response.use( (response) => { // 移除掛起的請求 removePendingRequest(response); const res = response.data; return res; }, (error) => { // 移除掛起的請求 removePendingRequest(error); // 是否是取消請求 if (Axios.isCancel(error)) { console.log("err:", error); return Promise.reject(error); } else { console.log("請求有問題:", error.message); // 當請求超時、斷網(wǎng)等問題時重發(fā) return againRequest(error); } } ); export default service; const pendingRequest = new Map(); /** * 添加待處理請求 * @description 該函數(shù)用于管理重復請求,避免同一接口的多個請求同時進行 * @param {Object} config - axios請求配置對象 */ function addPendingRequest(config) { // 創(chuàng)建axios的取消令牌源,用于請求的取消控制 const CancelToken = axios.CancelToken; const source = CancelToken.source(); // 生成請求的唯一鍵,用于標識不同的請求 const requestKey = generateReqKey(config); // 方法一 // 如果相同請求已在進行中,則取消當前請求 if (pendingRequest.has(requestKey)) { config.cancelToken = source.token; source.cancel(`${config.url} 請求已取消`); } else { // 如果沒有相同的請求在進行中,則設置取消令牌并存儲請求鍵和取消函數(shù)的映射 config.cancelToken = source.token; pendingRequest.set(requestKey, source.token); } // 方法二 // 如果相同請求已在進行中,則取消當前請求 if (pendingRequest.has(requestKey)) { config.cancelToken = new Axios.CancelToken((cancel) => { // cancel 函數(shù)的參數(shù)會作為 promise 的 error 被捕獲 cancel(`${config.url} 請求已取消`); }); } else { config.cancelToken = new Axios.CancelToken((cancel) => { pendingRequest.set(requestKey, cancel); }); } // 以上兩種方式都能取消請求,但是從 Axios `v0.22.0` 開始已被棄用,從 `v0.22.0` 開始,Axios 支持以 fetch API 方式—— `AbortController`取消請求 } /** * 移除掛起的請求 * @description 當收到響應時,檢查并移除與該響應相關的掛起請求 * @param {Object} response - 響應對象,包含請求配置信息 */ function removePendingRequest(response) { // 如果 response.config 返回的是 undefined,表示是取消請求,則不處理 if (response.config) { // 生成請求的唯一鍵,用于標識不同的請求 const requestKey = generateReqKey(response.config); // 判斷是否有這個 key,有就刪除 if (pendingRequest.has(requestKey)) { pendingRequest.delete(requestKey); } } } /** * 處理請求重試的函數(shù) * @description 它嘗試重新發(fā)送因錯誤而失敗的請求 * @param {Object} err - 包含錯誤信息和配置的對象 * @returns {Promise} 重新發(fā)送請求的Promise對象,解決或拒絕依據(jù)重試邏輯 */ function againRequest(err) { const config = err.config; // 如果配置對象不存在,則直接拒絕Promise if (!config) return Promise.reject(err); // 設置用于記錄重試計數(shù)的變量 默認為0 config._retryCount = config._retryCount || 0; // 如果重試次數(shù)已經(jīng)達到3次或更多,則拒絕Promise if (config._retryCount >= 3) { return Promise.reject(err); } // 重試次數(shù) config._retryCount += 1; // 延時處理,用于控制重試的時間間隔 var backoff = new Promise((resolve) => { setTimeout(() => { resolve(); }, 1000); }); // 在延時結束后,重新發(fā)起請求 return backoff.then(() => { // 重新發(fā)起axios請求,使用更新后的配置 return service(config); }); } /** * 生成請求的唯一鍵 * @description 這個函數(shù)的目的是根據(jù)請求配置生成一個唯一的鍵,用于緩存請求數(shù)據(jù) * @param {Object} config - 請求配置對象,包含了url、method、params和data屬性 * @returns {string} - 返回一個根據(jù)請求配置生成的唯一鍵 */ function generateReqKey(config) { // 請求得到的config.data是對象格式,響應回來的response.config.data是字符串格式,需要轉換成對象 if (typeof config.data === "string") { config.data = JSON.parse(config.data); } const { url, method, params, data } = config; return [url, method, JSON.stringify(params), JSON.stringify(data)].join("&"); }
實現(xiàn)2(取消前面的請求,只發(fā)出最后一個請求)
import Axios from "axios"; // 創(chuàng)建一個實例 const service = Axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 1000, }); // 添加請求攔截器 service.interceptors.request.use( (config) => { // 判斷是否有 token if (getToken()) { config.headers["Permission-Token"] = getToken(); } // 添加待處理請求 addPendingRequest(config); return config; }, (error) => { return Promise.reject(error); } ); // 添加響應攔截器 service.interceptors.response.use( (response) => { const res = response.data; return res; }, (error) => { // 是否是取消請求 if (!axios.isCancel(error)) { // 當請求超時、斷網(wǎng)等問題時重發(fā) againRequest(error); } } ); export default service; let pendingRequsetList = []; /** * 取消所有待處理的請求 */ export const cancelPendingRequest = () => { // 遍歷待處理的請求列表,調(diào)用每個請求的取消方法 pendingRequsetList.forEach((item) => { item.cancel(); }); // 清空待處理的請求列表 pendingRequsetList = []; }; /** * 添加待處理的請求 * @description 為配置對象添加取消令牌,以便在請求待處理時能夠取消 * @param {Object} config - 請求的配置對象 */ function addPendingRequest(config) { // 創(chuàng)建一個新的取消令牌,并將取消函數(shù)存儲到待處理請求列表中 config.cancelToken = new Axios.CancelToken((cancel) => { pendingRequsetList.push({ cancel, }); }); } /** * 處理請求失敗后的重試機制 * @description 當請求失敗時,嘗試再次請求,最多重試3次 * @param {Object} err - 錯誤對象,包含請求的配置信息 * @returns {Promise} 重試請求的Promise對象 */ function againRequest(err) { // 獲取請求的配置信息 const config = err.config; // 如果沒有配置信息,則直接拒絕Promise if (!config) Promise.reject(err); // 初始化重試次數(shù),如果不存在則為0 config._retryCount = config._retryCount || 0; // 如果重試次數(shù)已經(jīng)達到3次,則拒絕Promise if (config._retryCount >= 3) { return Promise.reject(err); } // 每次重試前,重試次數(shù)加1 config._retryCount += 1; // 創(chuàng)建一個Promise,用于實現(xiàn)指數(shù)退避機制 const backoff = new Promise((resolve) => { // 設置一個定時器,1秒后 resolve Promise setTimeout(() => { resolve(); }, 1000); }); // 返回一個Promise,表示再次請求的操作 return backoff.then(() => { return service(config); }); }
在組件中使用,發(fā)送一個新的請求之前,取消前面的所有正在請求的請求,如下:
<script> import { cancelPendingRequest } from '@/utils/request' // 導入取消請求的方法 export default { methods: { getList() { cancelPendingRequest() // 取消所有正在發(fā)送請求的請求 axios.get() // 發(fā)送新的請求 } } } </script>
如果不想每次使用取消請求的時候都需要導入那么可以掛載到Vue的原型上面,可以在main.js
文件中
import Vue from 'vue' import { cancelPendingRequest } from '@/utils/request' Vue.prototype.$cancelPendingRequest = cancelPendingRequest // 掛載到 Vue 原型上
另外如果想每次路由頁面跳轉時,取消上一個頁面的所有請求,我們可以在全局路由守衛(wèi)那里進行處理,具體如下:
import router from "./router"; import Vue from 'vue' router.beforeEach((to, from, next) => { Vue.$cancelPendingRequest() // 跳轉頁面之前取消之前的所有請求 })
以上就是Vue Axios請求取消和重發(fā)的封裝的實現(xiàn)的詳細內(nèi)容,更多關于Vue Axios請求取消和重發(fā)的資料請關注腳本之家其它相關文章!
相關文章
VUE使用DXFParser組件解析dxf文件生成圖片的操作代碼
這篇文章主要介紹了VUE使用DXFParser組件解析dxf文件生成圖片的操作代碼,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-09-09Vuex子模塊調(diào)用子模塊的actions或mutations實現(xiàn)方式
這篇文章主要介紹了Vuex子模塊調(diào)用子模塊的actions或mutations實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10Element-UI組件實現(xiàn)面包屑導航欄的示例代碼
面包屑導航欄是一種用戶界面組件,用于展示用戶在網(wǎng)站或應用中的路徑,它包括了從主頁到當前頁面的鏈接序列,有助于用戶快速了解和導航至上級頁面,本文就來介紹一下Element-UI組件實現(xiàn)面包屑導航欄的示例代碼,感興趣的可以了解一下2024-09-09vue中el-autocomplete與el-select的異同
本文主要介紹了vue中el-autocomplete與el-select的異同,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-05-05ElementUI組件Dialog彈窗再次打開表單仍顯示上次數(shù)據(jù)的問題
這篇文章主要介紹了ElementUI組件Dialog彈窗再次打開表單仍顯示上次數(shù)據(jù)的問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04springboot?vue接口測試前端動態(tài)增刪表單功能實現(xiàn)
這篇文章主要為大家介紹了springboot?vue接口測試前端動態(tài)增刪表單功能實現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-05-05Vue3+X6流程圖實現(xiàn)數(shù)據(jù)雙向綁定詳解
這篇文章主要為大家詳細介紹了Vue3如何結合X6流程圖實現(xiàn)數(shù)據(jù)雙向綁定,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下2024-03-03