在 JavaScript 中,防抖函数(debounce)可通过延迟执行并清除之前的定时器实现,核心逻辑是确保事件停止触发一段时间后才执行回调。 以下是详细实现、优化及测试方法:
一、基础防抖函数实现function debounce(func, delay) { let timeoutId; return function(...args) { const context = this; clearTimeout(timeoutId); // 清除之前的定时器 timeoutId = setTimeout(() => { func.apply(context, args); // 延迟后执行回调 }, delay); };}- 作用:延迟执行回调,若延迟期间再次触发则重新计时。
- 适用场景:输入搜索、窗口调整、滚动事件等高频触发场景。
- 示例:function handleInput(e) { console.log('Input:', e.target.value); }const debouncedInput = debounce(handleInput, 300);// <input oninput="debouncedInput(event)">
二、防抖与节流的区别三、优化防抖函数(添加 leading 和 trailing 选项)function debounce(func, delay, options = { leading: false, trailing: true }) { let timeoutId; let lastArgs; let lastThis; const { leading, trailing } = options; function invokeFunc() { timeoutId = null; if (lastArgs) { func.apply(lastThis, lastArgs); lastArgs = lastThis = null; } } return function(...args) { lastArgs = args; lastThis = this; if (!timeoutId) { if (leading) { // 首次触发立即执行 func.apply(this, args); } timeoutId = setTimeout(invokeFunc, delay); } else { clearTimeout(timeoutId); // 重新计时 timeoutId = setTimeout(invokeFunc, delay); } };}四、测试防抖函数使用 Jest 测试框架验证以下场景:
- 延迟时间内多次触发,仅执行一次:it('should execute once after delay when triggered multiple times', () => { const func = jest.fn(); const debouncedFunc = debounce(func, 100); debouncedFunc(); debouncedFunc(); debouncedFunc(); jest.advanceTimersByTime(100); expect(func).toHaveBeenCalledTimes(1);});
- 延迟时间内无再次触发,延迟结束后执行:it('should execute after delay when no further triggers', () => { const func = jest.fn(); const debouncedFunc = debounce(func, 100); debouncedFunc(); expect(func).not.toHaveBeenCalled(); jest.advanceTimersByTime(100); expect(func).toHaveBeenCalledTimes(1);});
- leading: true 时首次立即执行:it('should execute immediately when leading is true', () => { const func = jest.fn(); const debouncedFunc = debounce(func, 100, { leading: true }); debouncedFunc(); expect(func).toHaveBeenCalledTimes(1);});
- trailing: false 时禁止延迟后执行:it('should not execute after delay when trailing is false', () => { const func = jest.fn(); const debouncedFunc = debounce(func, 100, { trailing: false }); debouncedFunc(); jest.advanceTimersByTime(100); expect(func).not.toHaveBeenCalled();});
五、防抖函数的应用价值- 性能优化:减少高频事件(如 scroll、resize)的回调执行次数,避免卡顿。
- 用户体验:例如搜索框输入时,延迟请求避免服务器过载,同时保证响应速度。
- 代码健壮性:通过 leading/trailing 选项灵活控制执行时机,适应不同场景需求。
通过上述实现与测试,防抖函数可有效平衡性能与功能需求,是处理高频事件的常用工具。