成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

聊聊 Ahooks 是怎么解決用戶(hù)多次提交問(wèn)題?

開(kāi)發(fā) 前端
通過(guò) axios 攔截器以及其 CancelToken 功能,我們能夠在攔截器中自動(dòng)將已發(fā)的請(qǐng)求取消,當(dāng)然假如有一些接口就是需要重復(fù)發(fā)送請(qǐng)求,可以考慮加一下白名單功能,讓請(qǐng)求不進(jìn)行取消。

本文來(lái)探索一下 ahooks 的 useLockFn。

場(chǎng)景

試想一下,有這么一個(gè)場(chǎng)景,有一個(gè)表單,你可能多次提交,就很可能導(dǎo)致結(jié)果不正確。

解決這類(lèi)問(wèn)題的方法有很多,比如添加 loading,在第一次點(diǎn)擊之后就無(wú)法再次點(diǎn)擊。另外一種方法就是給請(qǐng)求異步函數(shù)添加上一個(gè)靜態(tài)鎖,防止并發(fā)產(chǎn)生。這就是 ahooks 的 useLockFn 做的事情。

useLockFn

useLockFn 用于給一個(gè)異步函數(shù)增加競(jìng)態(tài)鎖,防止并發(fā)執(zhí)行。

它的源碼比較簡(jiǎn)單,如下所示:

import { useRef, useCallback } from 'react';
// 用于給一個(gè)異步函數(shù)增加競(jìng)態(tài)鎖,防止并發(fā)執(zhí)行。
function useLockFn<P extends any[] = any[], V extends any = any>(fn: (...args: P) => Promise<V>) {
// 是否現(xiàn)在處于一個(gè)鎖中
const lockRef = useRef(false);
// 返回的是增加了競(jìng)態(tài)鎖的函數(shù)
return useCallback(
async (...args: P) => {
// 判斷請(qǐng)求是否正在進(jìn)行
if (lockRef.current) return;
// 請(qǐng)求中
lockRef.current = true;
try {
// 執(zhí)行原有請(qǐng)求
const ret = await fn(...args);
// 請(qǐng)求完成,狀態(tài)鎖設(shè)置為 false
lockRef.current = false;
return ret;
} catch (e) {
// 請(qǐng)求失敗,狀態(tài)鎖設(shè)置為 false
lockRef.current = false;
throw e;
}
},
[fn],
);
}
export default useLockFn;

可以看到,它的入?yún)⑹钱惒胶瘮?shù),返回的是一個(gè)增加了競(jìng)態(tài)鎖的函數(shù)。通過(guò) lockRef 做一個(gè)標(biāo)識(shí)位,初始化的時(shí)候它的值為 false。當(dāng)正在請(qǐng)求,則設(shè)置為 true,從而下次再調(diào)用這個(gè)函數(shù)的時(shí)候,就直接 return,不執(zhí)行原函數(shù),從而達(dá)到加鎖的目的。

缺點(diǎn)

雖然實(shí)用,但缺點(diǎn)很明顯,我需要給每一個(gè)需要添加競(jìng)態(tài)鎖的請(qǐng)求異步函數(shù)都手動(dòng)加一遍。那有沒(méi)有比較通用和方便的方法呢?

答案是可以通過(guò) axios 自動(dòng)取消重復(fù)請(qǐng)求。

axios 自動(dòng)取消重復(fù)請(qǐng)求

axios 取消請(qǐng)求

對(duì)于原生的 XMLHttpRequest 對(duì)象發(fā)起的 HTTP 請(qǐng)求,可以調(diào)用 XMLHttpRequest 對(duì)象的 abort 方法。

那么我們項(xiàng)目中常用的 axios 呢?它其實(shí)底層也是用的 XMLHttpRequest 對(duì)象,它對(duì)外暴露取消請(qǐng)求的 API 是 CancelToken。可以使用如下:

const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.post('/user/12345', {
name: 'gopal'
}, {
cancelToken: source.token
})
source.cancel('Operation canceled by the user.'); // 取消請(qǐng)求,參數(shù)是可選的

另外一種使用的方法是調(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)求

如何自動(dòng)取消重復(fù)的請(qǐng)求

知道了如何取消請(qǐng)求,那怎么做到自動(dòng)取消呢?答案是通過(guò) axios 的攔截器。

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

具體的做法如下:

第一步,定義幾個(gè)重要的輔助函數(shù)。

  • generateReqKey:用于根據(jù)當(dāng)前請(qǐng)求的信息,生成請(qǐng)求 Key。只有 key 相同才會(huì)判定為是重復(fù)請(qǐng)求。這一點(diǎn)很重要,而且可能跟具體的業(yè)務(wù)場(chǎng)景有關(guān),比如有一種請(qǐng)求,輸入框模糊搜索,用戶(hù)高頻輸入關(guān)鍵字,一次性發(fā)出多個(gè)請(qǐng)求,可能先發(fā)出的請(qǐng)求,最后才響應(yīng),導(dǎo)致實(shí)際搜索結(jié)果與預(yù)期不符。這種其實(shí)就只需要根據(jù) URL 和請(qǐng)求方法判定其為重復(fù)請(qǐng)求,然后取消之前的請(qǐng)求就可以了。

這里我認(rèn)為,如果有需要的話(huà),可以暴露一個(gè) API 給開(kāi)發(fā)者進(jìn)行自定義重復(fù)的規(guī)則。這里我們先根據(jù)請(qǐng)求方法、url、以及參數(shù)生成唯一的 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);
}
}

第二步,添加請(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);
}
);

第二步,添加響應(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);
}
);

到這一步,我們就通過(guò) axios 完成了自動(dòng)取消重復(fù)請(qǐng)求的功能。

思考與總結(jié)

雖然可以通過(guò)類(lèi)似 useLockFn 這樣的 hook或方法給請(qǐng)求函數(shù)添加競(jìng)態(tài)鎖的方式解決重復(fù)請(qǐng)求的問(wèn)題。但這種還是需要依賴(lài)于開(kāi)發(fā)者的習(xí)慣,如果沒(méi)有一些規(guī)則的約束,很難避免問(wèn)題。

通過(guò) axios 攔截器以及其 CancelToken 功能,我們能夠在攔截器中自動(dòng)將已發(fā)的請(qǐng)求取消,當(dāng)然假如有一些接口就是需要重復(fù)發(fā)送請(qǐng)求,可以考慮加一下白名單功能,讓請(qǐng)求不進(jìn)行取消。

參考

  • Axios 如何取消重復(fù)請(qǐng)求?

參考資料

[1]詳情: https://github.com/GpingFeng/hooks。

責(zé)任編輯:姜華 來(lái)源: 前端雜貨鋪
相關(guān)推薦

2022-06-08 08:01:20

useEffect數(shù)組函數(shù)

2022-07-01 07:31:18

AhooksDOM場(chǎng)景

2024-05-31 09:31:00

2021-07-02 07:06:20

調(diào)試代碼crash

2022-09-28 11:34:27

用戶(hù)行為數(shù)據(jù)業(yè)務(wù)

2021-09-26 06:43:07

MySQL深分頁(yè)優(yōu)化

2021-11-09 10:20:15

MySQL深分頁(yè)數(shù)據(jù)庫(kù)

2021-09-27 13:33:03

MySQL深分頁(yè)數(shù)據(jù)庫(kù)

2019-11-26 16:32:41

區(qū)塊鏈信任問(wèn)題

2022-11-17 07:43:13

2023-02-26 08:42:10

源碼demouseEffect

2010-09-30 15:10:12

Javascriptimg

2010-10-08 15:35:32

Javascriptimg

2024-03-27 07:55:58

SpringRedis海量

2021-08-10 07:00:01

Redis單線(xiàn)程并發(fā)

2022-07-27 08:52:10

MySQL二階段提交

2022-06-10 08:01:01

ahookshook代碼

2021-02-05 08:42:21

云原生系統(tǒng)方式

2022-03-18 10:43:12

WebSocketHTML5TCP 連接

2024-02-21 08:19:54

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 国产精品国产三级国产aⅴ无密码 | 欧美国产日本一区 | 欧美一级全黄 | 中文精品视频 | 婷婷去俺也去 | 久久中文字幕一区 | 91在线成人| 久久国产精品-国产精品 | 久草热8精品视频在线观看 午夜伦4480yy私人影院 | 日韩免费视频 | 久久精品二区 | 黄色免费三级 | www.午夜| 五月婷婷导航 | 日本精品一区二区三区在线观看视频 | 天天操人人干 | 青草青草久热精品视频在线观看 | 精品久久久久久一区二区 | 亚洲国产一区二区三区 | 午夜一区二区三区在线观看 | 久久日韩精品一区二区三区 | 精品一区二区在线观看 | 国产日韩欧美在线 | 久久精品国产清自在天天线 | 欧美日韩亚洲系列 | 国产欧美精品在线观看 | 精品成人在线观看 | 成年人黄色免费视频 | 一区二区三区国产在线观看 | 亚洲一区二区在线免费观看 | 国产视频2021 | 色婷婷一区| 黄片毛片在线观看 | 国产高清精品一区二区三区 | 日韩一区二区三区av | 91麻豆精品一区二区三区 | 99久久精品国产毛片 | 成人h视频在线 | 福利视频网站 | 久亚州在线播放 | 91精品久久久久久综合五月天 |