Content

JS实现上次操作未完成禁止新操作逻辑特事特办方案(js实现上次操作未完成禁止新操作怎么办)没想到

文章摘要

文章主要讨论了如何在JavaScript中处理异步操作的条件式回调问题,特别是按钮点击事件期间防止多次请求的处理。文章介绍了四种解决方案: 1. **自定义回调函数**:通过锁定机制实现。当第一次点击按钮时,触发回调并设置锁定状态为true;在锁定状态为true时返回,防止后续请求。 2. **基于Promise的条件式回调**:利用Promise的try-catch机制,将回调函数的返回值改为Promise。通过捕获完成时的钩子,实现锁定状态的控制。 3. **React hook版本**:使用React hook提供更优雅、更通用的解决方案。通过ref对象管理锁定状态,并将回调函数封装为一个可复用的钩子。 文章的核心观点是:虽然防抖和节流可以实现类似的“特事特办”效果,但它们需要依赖时间戳来判断执行条件,而条件式回调需要更灵活的机制来实现同样的效果。特别是,当需要对原回调函数的参数进行改写时,自定义回调或React hook会更优。 总结:文章通过具体的实现案例,展示了如何在JavaScript中实现条件式回调的防抖机制,并对比了不同解决方案的优劣。


目录场景1.初步解决方案:特事特办2. 基于约定回调的条件式回调函数3. 基于 Promise 的条件式回调函数4. React hook 版

相信很多人都遇到过类似的场景:

某一个按钮是用来发送请求的,并且需要一段时间来处理。但是用户往往会在处理期间有意或无意地点击多次,因此我们希望在上一次发出的请求处理完毕之前,不再发出新的请求。

“特事特办”的意思,就是每次遇到这样的场景,都特意写一段逻辑来处理:

document.addEventListener(‘click’, (()=> { let lock=false; return ()=> { if(lock) return; lock=true; console.log(‘clicked’); // 为了方便测试就使用延时了 setTimeout(()=> { lock=false; }, Math.random() * 4e3) } })());

上面的写法其实也不费事,但是这种条件限制能不能像已经被面试问烂了的“节流”和“防抖

”那样,用一个函数把它包裹起来就可以达成效果呢?

问题的关键其实在于:防抖和节流需要考虑的执行条件是时间,这个条件对于所有函数而言都是一个“共同的语言”,因此才双方可以做到那样的“默契”。

而要在这种场景里实现同样的效果,双方需要刻意的约定:例如被条件执行的函数额外接受一个函数,用于在合适的时机解除条件限制。
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); } }

  为了方便描述这种约定对 的要求,这里使用 TS 而不是 JS。

使用的时候:

button.addEventListener(‘click’, conditioned((release)=> { return ()=> { console.log(‘clicked’); setTimeout(()=> { release(); // 释放 lock }, Math.random() * 4e3); } }));

如果说有什么方法能比回调函数更“优雅”、更“通用”一些,答案显然是。

因为上面的写法对原来的回调函数的参数进行了改写,遇到一个爱好 Ctrl + C 的初学者的话,他会疑惑复制过来的函数为什么就不工作了。

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); }); }));

虽然乍一看,使用这个函数意味着必须把回调函数的返回值改写成 ,不过由于这种场景往往都是异步操作,改成  何乐而不为呢?

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>

 实际上没测试过,不知道行不行的,更多关于JS 上次未完成禁止新操作的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:JS表单验证插件之数据与逻辑分离操作实例分析【策略模式】JS基础之逻辑结构与循环操作示例图形编辑器中JS实现防误操作之拖拽阻塞Node.js?内置模块fs文件系统操作示例详解JS实现简单的操作杆旋转示例详解