js如何实现防抖函数 防抖函数的3种经典实现方案

js如何实现防抖函数 防抖函数的3种经典实现方案
最新回答
喂,把心还给我

2020-11-03 09:46:21

防抖函数的核心是延迟执行并重置计时,确保最终只执行最后一次触发。以下是三种经典实现方案:

1. 基础防抖函数(延迟执行)

通过 setTimeout 延迟触发函数,若再次触发则清除原定时器并重新计时。

function debounce(func, delay) { let timeoutId; return function(...args) { const context = this; clearTimeout(timeoutId); timeoutId = setTimeout(() => { func.apply(context, args); }, delay); };}

示例

function sayHello(name) { console.log(`Hello, ${name}!`);}const debouncedHello = debounce(sayHello, 300);debouncedHello("Alice"); // 不会立即执行debouncedHello("Bob"); // 取消Alice的执行,重新计时setTimeout(() => debouncedHello("Charlie"), 200); // 取消Bob的执行setTimeout(() => debouncedHello("David"), 500); // 延迟500ms后执行

关键点

  • 使用 clearTimeout 清除未执行的定时器。
  • 通过 apply 确保上下文和参数正确传递。

2. 立即执行的防抖函数

首次触发时立即执行,后续触发在延迟时间内重新计时。

function debounceImmediate(func, delay) { let timeoutId; let isInvoked = false; return function(...args) { const context = this; if (!isInvoked) { func.apply(context, args); isInvoked = true; } clearTimeout(timeoutId); timeoutId = setTimeout(() => { isInvoked = false; }, delay); };}

示例

function sayHelloImmediate(name) { console.log(`Hello (Immediate), ${name}!`);}const debouncedHelloImmediate = debounceImmediate(sayHelloImmediate, 300);debouncedHelloImmediate("Eve"); // 立即执行debouncedHelloImmediate("Frank"); // 不会立即执行,但会重置计时setTimeout(() => debouncedHelloImmediate("Grace"), 500); // 延迟500ms后执行

关键点

  • 引入 isInvoked 变量控制首次是否立即执行。
  • 适用于需要立即响应的场景(如搜索框输入)。

3. 带取消功能的防抖函数

通过添加 cancel 方法手动取消未执行的防抖函数。

function debounceWithCancel(func, delay) { let timeoutId; function debounced(...args) { const context = this; clearTimeout(timeoutId); timeoutId = setTimeout(() => { func.apply(context, args); }, delay); } debounced.cancel = () => { clearTimeout(timeoutId); }; return debounced;}

示例

function sayHelloCancelable(name) { console.log(`Hello (Cancelable), ${name}!`);}const debouncedHelloCancelable = debounceWithCancel(sayHelloCancelable, 300);debouncedHelloCancelable("Henry"); // 触发防抖setTimeout(() => debouncedHelloCancelable.cancel(), 200); // 取消执行setTimeout(() => debouncedHelloCancelable("Ivy"), 500); // 延迟500ms后执行

关键点

  • 通过 cancel 方法清除定时器,阻止函数执行。
  • 适用于需要动态控制执行流程的场景。

补充说明
  • 为什么用 apply:确保函数在正确的上下文中执行,并传递正确的参数。直接调用 func() 可能导致 this 指向错误(如全局对象)。
  • 防抖 vs 节流

    防抖:最后一次触发有效,适用于搜索建议、窗口调整。

    节流:一段时间内仅执行一次,适用于滚动事件、鼠标移动。

  • 常见应用场景

    搜索建议:用户停止输入后发送请求。

    窗口调整:调整完成后重新计算布局。

    按钮防重复点击:防止表单重复提交。

    文本自动保存:用户停止编辑后保存。

通过以上三种方案,可以灵活应对不同场景下的防抖需求。