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

Vue?Axios請求取消和重發(fā)封裝的實(shí)現(xiàn)代碼

 更新時間:2024年09月12日 09:39:02   作者:墨辰mc  
這篇文章主要介紹了Vue?Axios請求取消和重發(fā)的封裝的實(shí)現(xiàn),文章通過代碼示例講解的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下

場景

如圖,有時候請求后端同一接口時,會因接口響應(yīng)速度過慢,導(dǎo)致前端原本頁面應(yīng)顯示a,結(jié)果顯示b。像上圖,前端頁面看起來就是先顯示 請求b 的數(shù)據(jù),然后是 請求c 的數(shù)據(jù),最后是 請求a 的數(shù)據(jù),但是實(shí)際上我們只需要顯示最后的 請求c 的數(shù)據(jù)。而且這樣還會導(dǎo)致頁面渲染出現(xiàn)閃爍。

需求

  • 實(shí)現(xiàn)取消重復(fù)請求(有多種取消方式)
    • 發(fā)出第一個請求,取消后面的相同請求
    • 取消前面的請求,只發(fā)出最后一個請求
  • 實(shí)現(xiàn)請求失敗后,自動重發(fā)指定次數(shù)

實(shí)現(xiàn)1(發(fā)出第一個請求,取消后面的相同請求)

import Axios from "axios";

// 創(chuàng)建一個實(shí)例
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);
  }
);

// 添加響應(yīng)攔截器
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);
      // 當(dāng)請求超時、斷網(wǎng)等問題時重發(fā)
      return againRequest(error);
    }
  }
);

export default service;

const pendingRequest = new Map();
/**
 * 添加待處理請求
 * @description 該函數(shù)用于管理重復(fù)請求,避免同一接口的多個請求同時進(jìn)行
 * @param {Object} config - axios請求配置對象
 */
function addPendingRequest(config) {
  // 創(chuàng)建axios的取消令牌源,用于請求的取消控制
  const CancelToken = axios.CancelToken;
  const source = CancelToken.source();

  // 生成請求的唯一鍵,用于標(biāo)識不同的請求
  const requestKey = generateReqKey(config);

  // 方法一
  // 如果相同請求已在進(jìn)行中,則取消當(dāng)前請求
  if (pendingRequest.has(requestKey)) {
    config.cancelToken = source.token;
    source.cancel(`${config.url} 請求已取消`);
  } else {
    // 如果沒有相同的請求在進(jìn)行中,則設(shè)置取消令牌并存儲請求鍵和取消函數(shù)的映射
    config.cancelToken = source.token;
    pendingRequest.set(requestKey, source.token);
  }
  
  // 方法二
  // 如果相同請求已在進(jìn)行中,則取消當(dāng)前請求
  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 當(dāng)收到響應(yīng)時,檢查并移除與該響應(yīng)相關(guān)的掛起請求
 * @param {Object} response - 響應(yīng)對象,包含請求配置信息
 */
function removePendingRequest(response) {
  // 如果 response.config 返回的是 undefined,表示是取消請求,則不處理
  if (response.config) {
    // 生成請求的唯一鍵,用于標(biāo)識不同的請求
    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è)置用于記錄重試計數(shù)的變量 默認(rèn)為0
  config._retryCount = config._retryCount || 0;

  // 如果重試次數(shù)已經(jīng)達(dá)到3次或更多,則拒絕Promise
  if (config._retryCount >= 3) {
    return Promise.reject(err);
  }
  // 重試次數(shù)
  config._retryCount += 1;

  // 延時處理,用于控制重試的時間間隔
  var backoff = new Promise((resolve) => {
    setTimeout(() => {
      resolve();
    }, 1000);
  });

  // 在延時結(jié)束后,重新發(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是對象格式,響應(yīng)回來的response.config.data是字符串格式,需要轉(zhuǎn)換成對象
  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("&");
}

實(shí)現(xiàn)2(取消前面的請求,只發(fā)出最后一個請求)

import Axios from "axios";

// 創(chuàng)建一個實(shí)例
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);
  }
);

// 添加響應(yīng)攔截器
service.interceptors.response.use(
  (response) => {
    const res = response.data;
    return res;
  },
  (error) => {
    // 是否是取消請求
    if (!axios.isCancel(error)) {
      // 當(dāng)請求超時、斷網(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,
    });
  });
}

/**
 * 處理請求失敗后的重試機(jī)制
 * @description 當(dāng)請求失敗時,嘗試再次請求,最多重試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)達(dá)到3次,則拒絕Promise
  if (config._retryCount >= 3) {
    return Promise.reject(err);
  }

  // 每次重試前,重試次數(shù)加1
  config._retryCount += 1;

  // 創(chuàng)建一個Promise,用于實(shí)現(xiàn)指數(shù)退避機(jī)制
  const backoff = new Promise((resolve) => {
    // 設(shè)置一個定時器,1秒后 resolve Promise
    setTimeout(() => {
      resolve();
    }, 1000);
  });

  // 返回一個Promise,表示再次請求的操作
  return backoff.then(() => {
    return service(config);
  });
}

在組件中使用,發(fā)送一個新的請求之前,取消前面的所有正在請求的請求,如下:

<script>
import { cancelPendingRequest } from '@/utils/request' // 導(dǎo)入取消請求的方法

export default {
  methods: {
    getList() {
      cancelPendingRequest() // 取消所有正在發(fā)送請求的請求
      axios.get() // 發(fā)送新的請求
    }
  }
}
</script>

如果不想每次使用取消請求的時候都需要導(dǎo)入那么可以掛載到Vue的原型上面,可以在main.js文件中

import Vue from 'vue'
import { cancelPendingRequest } from '@/utils/request'

Vue.prototype.$cancelPendingRequest = cancelPendingRequest // 掛載到 Vue 原型上

另外如果想每次路由頁面跳轉(zhuǎn)時,取消上一個頁面的所有請求,我們可以在全局路由守衛(wèi)那里進(jìn)行處理,具體如下:

import router from "./router";
import Vue from 'vue'

router.beforeEach((to, from, next) => {
   Vue.$cancelPendingRequest() // 跳轉(zhuǎn)頁面之前取消之前的所有請求
})

以上就是Vue Axios請求取消和重發(fā)的封裝的實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于Vue Axios請求取消和重發(fā)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論

洪雅县| 新绛县| 改则县| 昆山市| 十堰市| 蓝田县| 万宁市| 儋州市| 青海省| 白朗县| 界首市| 玉山县| 青浦区| 邯郸县| 富宁县| 当雄县| 株洲县| 泸定县| 湟中县| 芮城县| 鄂托克前旗| 讷河市| 谢通门县| 桦甸市| 香格里拉县| 馆陶县| 同江市| 奉节县| 建平县| 年辖:市辖区| 蓝山县| 东辽县| 青浦区| 化隆| 五华县| 敦煌市| 大城县| 自治县| 荣成市| 吴川市| 凤凰县|