JS實(shí)現(xiàn)"上次操作未完成禁止新操作"邏輯特事特辦方案
場(chǎng)景
相信很多人都遇到過(guò)類似的場(chǎng)景:
某一個(gè)按鈕是用來(lái)發(fā)送請(qǐng)求的,并且需要一段時(shí)間來(lái)處理。但是用戶往往會(huì)在處理期間有意或無(wú)意地點(diǎn)擊多次,因此我們希望在上一次發(fā)出的請(qǐng)求處理完畢之前,不再發(fā)出新的請(qǐng)求。
1.初步解決方案:特事特辦
“特事特辦”的意思,就是每次遇到這樣的場(chǎng)景,都特意寫(xiě)一段邏輯來(lái)處理:
document.addEventListener('click', (() => { let lock = false; return () => { if(lock) return; lock = true; console.log('clicked'); // 為了方便測(cè)試就使用延時(shí)了 setTimeout(() => { lock = false; }, Math.random() * 4e3) } })());
2. 基于約定回調(diào)的條件式回調(diào)函數(shù)
上面的寫(xiě)法其實(shí)也不費(fèi)事,但是這種條件限制能不能像已經(jīng)被面試問(wèn)爛了的“節(jié)流”和“防抖”那樣,用一個(gè)函數(shù)把它包裹起來(lái)就可以達(dá)成效果呢?
問(wèn)題的關(guān)鍵其實(shí)在于:防抖和節(jié)流需要考慮的執(zhí)行條件是時(shí)間,這個(gè)條件對(duì)于所有函數(shù)而言都是一個(gè)“共同的語(yǔ)言”,因此才雙方可以做到那樣的“默契”。
而要在這種場(chǎng)景里實(shí)現(xiàn)同樣的效果,雙方需要刻意的約定:例如被條件執(zhí)行的函數(shù)額外接受一個(gè)函數(shù),用于在合適的時(shí)機(jī)解除條件限制。
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); } }
?? 為了方便描述這種約定對(duì)callback
的要求,這里使用 TS 而不是 JS。
使用的時(shí)候:
button.addEventListener('click', conditioned((release) => { return () => { console.log('clicked'); setTimeout(() => { release(); // 釋放 lock }, Math.random() * 4e3); } }));
3. 基于 Promise 的條件式回調(diào)函數(shù)
如果說(shuō)有什么方法能比回調(diào)函數(shù)更“優(yōu)雅”、更“通用”一些,答案顯然是Promise
。
因?yàn)樯厦娴膶?xiě)法對(duì)原來(lái)的回調(diào)函數(shù)的參數(shù)進(jìn)行了改寫(xiě),遇到一個(gè)愛(ài)好 Ctrl + C 的初學(xué)者的話,他會(huì)疑惑復(fù)制過(guò)來(lái)的函數(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); }); }));
雖然乍一看,使用這個(gè)函數(shù)意味著必須把回調(diào)函數(shù)的返回值改寫(xiě)成 Promise
,不過(guò)由于這種場(chǎng)景往往都是異步操作,改成 async
何樂(lè)而不為呢?
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); }); })} >測(cè)試</button>
??實(shí)際上沒(méi)測(cè)試過(guò),不知道行不行的,更多關(guān)于JS 上次未完成禁止新操作的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
利用JS實(shí)現(xiàn)加減簡(jiǎn)易計(jì)算器
這篇文章主要為大家詳細(xì)介紹了如何利用JavaScript制作一個(gè)簡(jiǎn)單的網(wǎng)頁(yè)版加減計(jì)算器,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-05-05多種js圖片預(yù)加載實(shí)現(xiàn)方式分享
這篇文章主要為大家詳細(xì)介紹了多種js圖片預(yù)加載實(shí)現(xiàn)方式,包括html標(biāo)簽或css加載圖片、純js實(shí)現(xiàn)預(yù)加載,感興趣的小伙伴們可以參考一下2016-02-02QRCode.js二維碼生成并能長(zhǎng)按識(shí)別
這篇文章主要為大家詳細(xì)介紹了QRCode.js二維碼生成并能長(zhǎng)按識(shí)別,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-10-10javascript正則表達(dá)配置擴(kuò)展名并實(shí)現(xiàn)驗(yàn)證
這篇文章主要介紹了javascript正則表達(dá)配置擴(kuò)展名并實(shí)現(xiàn)驗(yàn)證,文章圍繞主題展開(kāi)相關(guān)資料,具有以得參考價(jià)值,需要的小伙伴可以參考一下2022-02-02JavaScript編寫(xiě)點(diǎn)擊查看大圖的頁(yè)面半透明遮罩層效果實(shí)例
這篇文章主要介紹了JavaScript制作點(diǎn)擊查看大圖的頁(yè)面遮罩層效果實(shí)例,透明部分這里使用的是CSS3的rgba,兼容性還是過(guò)得去的,需要的朋友可以參考下2016-05-05一個(gè)關(guān)于javascript匿名函數(shù)的問(wèn)題分析
一個(gè)關(guān)于javascript匿名函數(shù)的問(wèn)題分析,學(xué)習(xí)js的朋友可以參考下2012-03-03小程序如何獲取多個(gè)formId實(shí)現(xiàn)詳解
這篇文章主要介紹了小程序如何獲取多個(gè)formId實(shí)現(xiàn)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09