如何实现事件处理throttle/debounce的专属超时变量 避免全局冲突
实现思路
通过高阶函数创建独立闭包存储每个处理函数专属的timeout ID,完全避免全局变量冲突,同时生成的包装函数为固定引用,完全兼容事件监听器的添加/移除规则。
防抖(delay)函数实现
/** * 创建防抖处理函数 * @param {Function} handler 实际要执行的业务处理函数 * @param {Number} delay 防抖等待时长(毫秒) * @returns {Function} 包装后的防抖事件处理函数 */ function createDebounce(handler, delay) { let timeoutId = null; return function(event) { clearTimeout(timeoutId); timeoutId = setTimeout(() => handler(event), delay); }; }
节流(throttle)函数实现
/** * 创建节流处理函数 * @param {Function} handler 实际要执行的业务处理函数 * @param {Number} delay 节流间隔时长(毫秒) * @returns {Function} 包装后的节流事件处理函数 */ function createThrottle(handler, delay) { let timeoutId = null; return function(event) { if (!timeoutId) { timeoutId = setTimeout(() => { timeoutId = null; handler(event); }, delay, event); } }; }
使用示例
JS代码:
// 业务处理函数 const resizeHandler = (event) => console.log(event.type); const mousemoveHandler = (event) => console.log(event.type); // 生成专属的防抖/节流处理函数,每个都有独立的timeout状态 const delayedResizeHandler = createDebounce(resizeHandler, 167); const throttledMousemoveHandler = createThrottle(mousemoveHandler, 66); // 添加监听 window.addEventListener('resize', delayedResizeHandler); window.addEventListener('mousemove', throttledMousemoveHandler); // 移除监听,直接使用生成的包装函数引用即可 document.querySelector('#resize').addEventListener('click', () => { window.removeEventListener('resize', delayedResizeHandler); }); document.querySelector('#mousemove').addEventListener('click', () => { window.removeEventListener('mousemove', throttledMousemoveHandler); });
HTML代码和原有逻辑完全兼容:
<button id="resize" type="button">Remove resize handler</button> <button id="mousemove" type="button">Remove mousemove handler</button>
方案优势
- 无全局状态依赖,每调用一次
createDebounce/createThrottle生成的处理函数都持有独立的闭包变量存储timeout ID,多个处理函数之间完全不会互相干扰 - 生成的包装函数引用固定,完全符合DOM事件监听添加、移除的规则,使用方式和普通事件处理函数没有差异
- 可扩展性强,后续需要支持立即执行、取消等待中等能力时,只需在闭包内添加对应逻辑即可
内容的提问来源于stack exchange,提问作者benvc
相关产品推荐
相关产品推荐

