JS實現(xiàn)"上次操作未完成禁止新操作"邏輯特事特辦方案
場景
相信很多人都遇到過類似的場景:
某一個按鈕是用來發(fā)送請求的,并且需要一段時間來處理。但是用戶往往會在處理期間有意或無意地點擊多次,因此我們希望在上一次發(fā)出的請求處理完畢之前,不再發(fā)出新的請求。
1.初步解決方案:特事特辦
“特事特辦”的意思,就是每次遇到這樣的場景,都特意寫一段邏輯來處理:
document.addEventListener('click', (() => {
let lock = false;
return () => {
if(lock) return;
lock = true;
console.log('clicked');
// 為了方便測試就使用延時了
setTimeout(() => {
lock = false;
}, Math.random() * 4e3)
}
})());2. 基于約定回調(diào)的條件式回調(diào)函數(shù)
上面的寫法其實也不費事,但是這種條件限制能不能像已經(jīng)被面試問爛了的“節(jié)流”和“防抖”那樣,用一個函數(shù)把它包裹起來就可以達成效果呢?
問題的關(guān)鍵其實在于:防抖和節(jié)流需要考慮的執(zhí)行條件是時間,這個條件對于所有函數(shù)而言都是一個“共同的語言”,因此才雙方可以做到那樣的“默契”。
而要在這種場景里實現(xiàn)同樣的效果,雙方需要刻意的約定:例如被條件執(zhí)行的函數(shù)額外接受一個函數(shù),用于在合適的時機解除條件限制。
function conditioned(callback:(release:Function,...args:any[]) => any){
let lock = false;
return function(...args:any[]){
if(lock) return;
lock = true;
callback.call(this, () => {
lock = false;
}, ...args);
}
} ?? 為了方便描述這種約定對callback 的要求,這里使用 TS 而不是 JS。
使用的時候:
button.addEventListener('click', conditioned((release) => {
return () => {
console.log('clicked');
setTimeout(() => {
release(); // 釋放 lock
}, Math.random() * 4e3);
}
}));3. 基于 Promise 的條件式回調(diào)函數(shù)
如果說有什么方法能比回調(diào)函數(shù)更“優(yōu)雅”、更“通用”一些,答案顯然是Promise。
因為上面的寫法對原來的回調(diào)函數(shù)的參數(shù)進行了改寫,遇到一個愛好 Ctrl + C 的初學(xué)者的話,他會疑惑復(fù)制過來的函數(shù)為什么就不工作了。
function conditioned(callback:(...args:any[]) => Promise<any>){
let lock = false;
return function(...args:any[]){
if(lock) return;
lock = true;
try {
await callback.call(this, ...args);
lock = false;
} catch(err) {
lock = false;
throw err;
}
}
}使用方法:
button.addEventListener('click', conditioned(() => {
return new Promise((resolve) => {
console.log('clicked');
setTimeout(() => {
resolve(); // 釋放 lock
}, Math.random() * 4e3);
});
}));雖然乍一看,使用這個函數(shù)意味著必須把回調(diào)函數(shù)的返回值改寫成 Promise,不過由于這種場景往往都是異步操作,改成 async 何樂而不為呢?
4. React hook 版
import { useRef } from 'react';
function useCondition(callback: (...args: any[]) => Promise<any>) {
const lock = useRef(false);
return async (...args:any[]) => {
if(lock.current) return;
lock.current = true;
try{
await callback(...args);
lock.current = false
} catch(error){
lock.current = false;
throw error;
}
};
}使用方法:
<button
onClick={useCondition(() => {
return new Promise<void>((resolve) => {
console.log('clicked');
setTimeout(() => {
resolve(); // 釋放 lock
}, Math.random() * 4e3);
});
})}
>測試</button>??實際上沒測試過,不知道行不行的,更多關(guān)于JS 上次未完成禁止新操作的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用JavaScript給圖片添加水印的實現(xiàn)方法封裝
圖片加水印是一種常見的圖像處理技術(shù),通常用于保護版權(quán)、防止盜用、增加圖片的識別度等多種場景,這篇文章主要給大家介紹了關(guān)于使用JavaScript給圖片添加水印的實現(xiàn)方法封裝,需要的朋友可以參考下2024-03-03
layui字體圖標(biāo) loading圖標(biāo)靜止不旋轉(zhuǎn)的解決方法
今天小編就為大家分享一篇layui字體圖標(biāo) loading圖標(biāo)靜止不旋轉(zhuǎn)的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-09-09
JavaScript實現(xiàn)網(wǎng)頁tab欄效果制作
這篇文章主要為大家詳細介紹了JavaScript實現(xiàn)網(wǎng)頁tab欄效果制作,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-11-11
JSP防止網(wǎng)頁刷新重復(fù)提交數(shù)據(jù)的幾種方法
這篇文章主要介紹了JSP防止網(wǎng)頁刷新重復(fù)提交數(shù)據(jù)的幾種方法,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-11-11
服務(wù)器端的JavaScript腳本 Node.js 使用入門
觸爪伸向傳說中的Server-Side Javascrpt。后端JS最出名無疑是Ryan Dahl的node.js,另一個是aptana IDE提供商搞出的jaxer,這里討論node.js的使用2012-03-03

