欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Axios取消重復(fù)請(qǐng)求的方法實(shí)例詳解

 更新時(shí)間:2021年06月15日 09:45:07   作者:阿寶哥  
在開(kāi)發(fā)中,經(jīng)常會(huì)遇到接口重復(fù)請(qǐng)求導(dǎo)致的各種問(wèn)題,這篇文章主要給大家介紹了關(guān)于Axios取消重復(fù)請(qǐng)求的相關(guān)資料,需要的朋友可以參考下

前言

在 Web 項(xiàng)目開(kāi)發(fā)過(guò)程中,我們經(jīng)常會(huì)遇到重復(fù)請(qǐng)求的場(chǎng)景,如果系統(tǒng)不對(duì)重復(fù)的請(qǐng)求進(jìn)行處理,則可能會(huì)導(dǎo)致系統(tǒng)出現(xiàn)各種問(wèn)題。比如重復(fù)的 post 請(qǐng)求可能會(huì)導(dǎo)致服務(wù)端產(chǎn)生兩筆記錄。那么重復(fù)請(qǐng)求是如何產(chǎn)生的呢?這里我們舉 2 個(gè)常見(jiàn)的場(chǎng)景:

  • 假設(shè)頁(yè)面中有一個(gè)按鈕,用戶點(diǎn)擊按鈕后會(huì)發(fā)起一個(gè) AJAX 請(qǐng)求。如果未對(duì)該按鈕進(jìn)行控制,當(dāng)用戶快速點(diǎn)擊按鈕時(shí),則會(huì)發(fā)出重復(fù)請(qǐng)求。
  • 假設(shè)在考試結(jié)果查詢頁(yè)面中,用戶可以根據(jù) “已通過(guò)”、“未通過(guò)” 和 “全部” 3 種查詢條件來(lái)查詢考試結(jié)果。如果請(qǐng)求的響應(yīng)比較慢,當(dāng)用戶在不同的查詢條件之前快速切換時(shí),就會(huì)產(chǎn)生重復(fù)請(qǐng)求。

既然已經(jīng)知道重復(fù)請(qǐng)求是如何產(chǎn)生的,也知道了它會(huì)帶來(lái)一些問(wèn)題。接下來(lái),阿寶哥將以 Axios 為例,帶大家來(lái)一起解決重復(fù)請(qǐng)求的問(wèn)題。

一、如何取消請(qǐng)求

Axios 是一個(gè)基于 Promise 的 HTTP 客戶端,同時(shí)支持瀏覽器和 Node.js 環(huán)境。它是一個(gè)優(yōu)秀的 HTTP 客戶端,被廣泛地應(yīng)用在大量的 Web 項(xiàng)目中。對(duì)于瀏覽器環(huán)境來(lái)說(shuō),Axios 底層是利用 XMLHttpRequest 對(duì)象來(lái)發(fā)起 HTTP 請(qǐng)求。如果要取消請(qǐng)求的話,我們可以通過(guò)調(diào)用 XMLHttpRequest 對(duì)象上的 abort 方法來(lái)取消請(qǐng)求:

let xhr = new XMLHttpRequest();
xhr.open("GET", "https://developer.mozilla.org/", true);
xhr.send();
setTimeout(() => xhr.abort(), 300);

而對(duì)于 Axios 來(lái)說(shuō),我們可以通過(guò) Axios 內(nèi)部提供的 CancelToken 來(lái)取消請(qǐng)求:

const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.post('/user/12345', {
  name: 'semlinker'
}, {
  cancelToken: source.token
})

source.cancel('Operation canceled by the user.'); // 取消請(qǐng)求,參數(shù)是可選的

此外,你也可以通過(guò)調(diào)用 CancelToken 的構(gòu)造函數(shù)來(lái)創(chuàng)建 CancelToken,具體如下所示:

const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    cancel = c;
  })
});

cancel(); // 取消請(qǐng)求

現(xiàn)在我們已經(jīng)知道在 Axios 中如何使用 CancelToken 來(lái)取消請(qǐng)求了,那么 CancelToken 內(nèi)部是如何工作的呢?這里我們先記住這個(gè)問(wèn)題,后面阿寶哥將為你們揭開(kāi) CancelToken 背后的秘密。接下來(lái),我們來(lái)分析一下如何判斷重復(fù)請(qǐng)求。

二、如何判斷重復(fù)請(qǐng)求

當(dāng)請(qǐng)求方式、請(qǐng)求 URL 地址和請(qǐng)求參數(shù)都一樣時(shí),我們就可以認(rèn)為請(qǐng)求是一樣的。因此在每次發(fā)起請(qǐng)求時(shí),我們就可以根據(jù)當(dāng)前請(qǐng)求的請(qǐng)求方式、請(qǐng)求 URL 地址和請(qǐng)求參數(shù)來(lái)生成一個(gè)唯一的 key,同時(shí)為每個(gè)請(qǐng)求創(chuàng)建一個(gè)專(zhuān)屬的 CancelToken,然后把 key 和 cancel 函數(shù)以鍵值對(duì)的形式保存到 Map 對(duì)象中,使用 Map 的好處是可以快速的判斷是否有重復(fù)的請(qǐng)求:

import qs from 'qs'

const pendingRequest = new Map();
// GET -> params;POST -> data
const requestKey = [method, url, qs.stringify(params), qs.stringify(data)].join('&'); 
const cancelToken = new CancelToken(function executor(cancel) {
  if(!pendingRequest.has(requestKey)){
    pendingRequest.set(requestKey, cancel);
  }
})

當(dāng)出現(xiàn)重復(fù)請(qǐng)求的時(shí)候,我們就可以使用 cancel 函數(shù)來(lái)取消前面已經(jīng)發(fā)出的請(qǐng)求,在取消請(qǐng)求之后,我們還需要把取消的請(qǐng)求從 pendingRequest 中移除?,F(xiàn)在我們已經(jīng)知道如何取消請(qǐng)求和如何判斷重復(fù)請(qǐng)求,下面我們來(lái)介紹如何取消重復(fù)請(qǐng)求。

三、如何取消重復(fù)請(qǐng)求

因?yàn)槲覀冃枰獙?duì)所有的請(qǐng)求都進(jìn)行處理,所以我們可以考慮使用 Axios 的攔截器機(jī)制來(lái)實(shí)現(xiàn)取消重復(fù)請(qǐng)求的功能。Axios 為開(kāi)發(fā)者提供了請(qǐng)求攔截器和響應(yīng)攔截器,它們的作用如下:

  • 請(qǐng)求攔截器:該類(lèi)攔截器的作用是在請(qǐng)求發(fā)送前統(tǒng)一執(zhí)行某些操作,比如在請(qǐng)求頭中添加 token 字段。
  • 響應(yīng)攔截器:該類(lèi)攔截器的作用是在接收到服務(wù)器響應(yīng)后統(tǒng)一執(zhí)行某些操作,比如發(fā)現(xiàn)響應(yīng)狀態(tài)碼為 401 時(shí),自動(dòng)跳轉(zhuǎn)到登錄頁(yè)。

3.1 定義輔助函數(shù)

在配置請(qǐng)求攔截器和響應(yīng)攔截器前,阿寶哥先來(lái)定義 3 個(gè)輔助函數(shù):

generateReqKey:用于根據(jù)當(dāng)前請(qǐng)求的信息,生成請(qǐng)求 Key;
function generateReqKey(config) {
  const { method, url, params, data } = config;
  return [method, url, Qs.stringify(params), Qs.stringify(data)].join("&");
}

addPendingRequest:用于把當(dāng)前請(qǐng)求信息添加到pendingRequest對(duì)象中;

const pendingRequest = new Map();
function addPendingRequest(config) {
  const requestKey = generateReqKey(config);
  config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
    if (!pendingRequest.has(requestKey)) {
       pendingRequest.set(requestKey, cancel);
    }
  });
}

removePendingRequest:檢查是否存在重復(fù)請(qǐng)求,若存在則取消已發(fā)的請(qǐng)求。

function removePendingRequest(config) {
  const requestKey = generateReqKey(config);
  if (pendingRequest.has(requestKey)) {
     const cancelToken = pendingRequest.get(requestKey);
     cancelToken(requestKey);
     pendingRequest.delete(requestKey);
  }
}

創(chuàng)建好 generateReqKey、addPendingRequest 和 removePendingRequest 函數(shù)之后,我們就可以設(shè)置請(qǐng)求攔截器和響應(yīng)攔截器了。

3.2 設(shè)置請(qǐng)求攔截器

axios.interceptors.request.use(
  function (config) {
    removePendingRequest(config); // 檢查是否存在重復(fù)請(qǐng)求,若存在則取消已發(fā)的請(qǐng)求
    addPendingRequest(config); // 把當(dāng)前請(qǐng)求信息添加到pendingRequest對(duì)象中
    return config;
  },
  (error) => {
     return Promise.reject(error);
  }
);

3.3 設(shè)置響應(yīng)攔截器

axios.interceptors.response.use(
  (response) => {
     removePendingRequest(response.config); // 從pendingRequest對(duì)象中移除請(qǐng)求
     return response;
   },
   (error) => {
      removePendingRequest(error.config || {}); // 從pendingRequest對(duì)象中移除請(qǐng)求
      if (axios.isCancel(error)) {
        console.log("已取消的重復(fù)請(qǐng)求:" + error.message);
      } else {
        // 添加異常處理
      }
      return Promise.reject(error);
   }
);

由于完整的示例代碼內(nèi)容比較多,阿寶哥就不放具體的代碼了。感興趣的小伙伴,可以訪問(wèn)以下地址瀏覽示例代碼。

完整的示例代碼:https://gist.github.com/semlinker/e426780664f0186db434882f1e27ac3a

這里我們來(lái)看一下 Axios 取消重復(fù)請(qǐng)求示例的運(yùn)行結(jié)果:

從上圖可知,當(dāng)出現(xiàn)重復(fù)請(qǐng)求時(shí),之前已發(fā)送且未完成的請(qǐng)求會(huì)被取消掉。下面我們用一張流程圖來(lái)總結(jié)一下取消重復(fù)請(qǐng)求的處理流程:

最后,我們來(lái)回答前面留下的問(wèn)題,即 CancelToken 內(nèi)部是如何工作的?

四、CancelToken 的工作原理

在前面的示例中,我們是通過(guò)調(diào)用 CancelToken 構(gòu)造函數(shù)來(lái)創(chuàng)建 CancelToken 對(duì)象:

new axios.CancelToken((cancel) => {
  if (!pendingRequest.has(requestKey)) {
    pendingRequest.set(requestKey, cancel);
  }
})

所以接下來(lái),我們來(lái)分析 CancelToken 構(gòu)造函數(shù),該函數(shù)被定義在 lib/cancel/CancelToken.js 文件中:

// lib/cancel/CancelToken.js
function CancelToken(executor) {
  if (typeof executor !== 'function') {
    throw new TypeError('executor must be a function.');
  }

  var resolvePromise;
  this.promise = new Promise(function promiseExecutor(resolve) {
    resolvePromise = resolve;
  });

  var token = this;
  executor(function cancel(message) { // 設(shè)置cancel對(duì)象
    if (token.reason) {
      return; // Cancellation has already been requested
    }
    token.reason = new Cancel(message);
    resolvePromise(token.reason);
  });
}

由以上代碼可知,cancel 對(duì)象是一個(gè)函數(shù),當(dāng)我們調(diào)用該函數(shù)后,會(huì)創(chuàng)建 Cancel 對(duì)象并調(diào)用 resolvePromise 方法。該方法執(zhí)行后,CancelToken 對(duì)象上 promise 屬性所指向的 promise 對(duì)象的狀態(tài)將變?yōu)?resolved。那么這樣做的目的是什么呢?這里我們從 lib/adapters/xhr.js 文件中找到了答案:

// lib/adapters/xhr.js 
if (config.cancelToken) {
  config.cancelToken.promise.then(function onCanceled(cancel) {
    if (!request) { return; }
    request.abort(); // 取消請(qǐng)求
    reject(cancel);
    request = null;
  });
}

看完上述的內(nèi)容,可能有的小伙伴還不是很能理解 CancelToken 的工作原理,所以阿寶哥又畫(huà)了一張圖來(lái)幫助大家理解 CancelToken 的工作原理:

五、總結(jié)

本文介紹了在 Axios 中如何取消重復(fù)請(qǐng)求及 CancelToken 的工作原理,在后續(xù)的文章中,阿寶哥將會(huì)介紹在 Axios 中如何設(shè)置數(shù)據(jù)緩存,感興趣的小伙伴不要錯(cuò)過(guò)喲。如果你想了解 Axios 中 HTTP 攔截器及 HTTP 適配器的設(shè)計(jì)與實(shí)現(xiàn),可以閱讀77.9K 的 Axios 項(xiàng)目有哪些值得借鑒的地方 這篇文章。

到此這篇關(guān)于Axios取消重復(fù)請(qǐng)求的文章就介紹到這了,更多相關(guān)Axios取消重復(fù)請(qǐng)求內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

六、參考資源

相關(guān)文章

  • JavaScript實(shí)現(xiàn)控制并發(fā)請(qǐng)求數(shù)量的方法詳解

    JavaScript實(shí)現(xiàn)控制并發(fā)請(qǐng)求數(shù)量的方法詳解

    這篇文章主要為大家詳細(xì)介紹了JavaScript如何實(shí)現(xiàn)控制并發(fā)請(qǐng)求數(shù)量,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-02-02
  • Javascript實(shí)現(xiàn)DIV滾動(dòng)自動(dòng)滾動(dòng)到底部的代碼

    Javascript實(shí)現(xiàn)DIV滾動(dòng)自動(dòng)滾動(dòng)到底部的代碼

    一個(gè)比較特殊的客戶要求,在一個(gè)頁(yè)面用表格顯示數(shù)據(jù),數(shù)據(jù)量不是很多,不希望使用瀏覽器的滾動(dòng)條,只能在Div中滾動(dòng)table中的數(shù)據(jù),但是有個(gè)特殊的要求,就是必須將滾動(dòng)條自動(dòng)滾動(dòng)到底部
    2012-03-03
  • 詳談LABJS按需動(dòng)態(tài)加載js文件

    詳談LABJS按需動(dòng)態(tài)加載js文件

    為了提高頁(yè)面的打開(kāi)和加載速度,我們經(jīng)常把JS文件放在頁(yè)面的尾部,但是有些JS必須放在頁(yè)面前面,這樣就會(huì)增加頁(yè)面的加載時(shí)間;于是出現(xiàn)了按需動(dòng)態(tài)加載的概念,這個(gè)概念就是當(dāng)頁(yè)面需要用到這個(gè)JS文件或者CSS渲染文件的時(shí)候,在去請(qǐng)求這些文件,這樣就節(jié)省了頁(yè)面的加載時(shí)間
    2015-05-05
  • js實(shí)現(xiàn)導(dǎo)航吸頂效果

    js實(shí)現(xiàn)導(dǎo)航吸頂效果

    本文主要分享了js實(shí)現(xiàn)導(dǎo)航吸頂效果的示例代碼,具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-02-02
  • ES6 javascript中class類(lèi)的get與set用法實(shí)例分析

    ES6 javascript中class類(lèi)的get與set用法實(shí)例分析

    這篇文章主要介紹了ES6 javascript中class類(lèi)的get與set用法,結(jié)合具體實(shí)例形式分析了ES6中類(lèi)的get與set關(guān)鍵字使用方法,需要的朋友可以參考下
    2017-10-10
  • bootstrap table 多選框分頁(yè)保留示例代碼

    bootstrap table 多選框分頁(yè)保留示例代碼

    在使用bootstrap table的復(fù)選框功能的時(shí)候,由于采用服務(wù)端分頁(yè),當(dāng)在第一頁(yè)選擇了某些數(shù)據(jù),然后點(diǎn)擊第二頁(yè)選擇一些數(shù)據(jù),再次點(diǎn)回第一頁(yè),發(fā)現(xiàn)原先選擇的數(shù)據(jù)已經(jīng)清空了,原來(lái)的多選框并不支持翻頁(yè)保留多選數(shù)據(jù),怎么解決呢,下面小編給大家分享下解決思路
    2017-03-03
  • 探討JavaScript語(yǔ)句的執(zhí)行過(guò)程

    探討JavaScript語(yǔ)句的執(zhí)行過(guò)程

    本文給大家介紹JavaScript語(yǔ)句的執(zhí)行過(guò)程的相關(guān)知識(shí),對(duì)js語(yǔ)句執(zhí)行過(guò)程的相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧
    2016-01-01
  • JS復(fù)制對(duì)應(yīng)id的內(nèi)容到粘貼板(Ctrl+C效果)

    JS復(fù)制對(duì)應(yīng)id的內(nèi)容到粘貼板(Ctrl+C效果)

    這篇文章主要給大家介紹了利用JS實(shí)現(xiàn)復(fù)制指定對(duì)應(yīng)id的內(nèi)容到粘貼板(Ctrl+C效果),文中給出了詳細(xì)的介紹和示例代碼,有需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-01-01
  • 詳解如何利用chatgpt保護(hù)您的js代碼

    詳解如何利用chatgpt保護(hù)您的js代碼

    這篇文章主要為大家介紹了如何利用chatgpt保護(hù)您的js代碼詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • extjs4圖表繪制之折線圖實(shí)現(xiàn)方法分析

    extjs4圖表繪制之折線圖實(shí)現(xiàn)方法分析

    這篇文章主要介紹了extjs4圖表繪制之折線圖實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了extjs4繪制折線圖的相關(guān)操作技巧、實(shí)現(xiàn)方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2020-03-03

最新評(píng)論