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

防抖函数的核心是延迟执行并重置计时,适用于搜索建议等场景。具体实现通过settimeout延迟触发函数,若再次触发则清除原定时器并重新计时。对于需要立即执行的情况,可引入isinvoked变量控制首次执行。同时可通过添加cancel方法实现手动取消。使用apply确保上下文和参数正确传递。防抖与节流的区别在于防抖保证最后一次触发有效,而节流确保一段时间内仅执行一次。常见应用场景包括搜索建议、窗口调整、按钮防重复点击、文本自动保存等。

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

防抖函数的核心在于:在事件触发后,不是立即执行,而是等待一段时间,如果在这段时间内再次触发,就重新计时。最终只执行最后一次触发。

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

解决方案

防抖的本质是延迟执行,并且在延迟的过程中,如果再次触发,则重新计时。理解这一点,实现防抖就变得简单了。

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

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"); setTimeout(() => debouncedHello("Charlie"), 200); // 会取消Bob的执行 setTimeout(() => debouncedHello("David"), 500); // 延迟500ms,会执行

如何使用立即执行的防抖函数?

有时候,我们希望第一次触发事件时立即执行,而不是等待。可以修改防抖函数来实现:

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

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变量,控制首次是否立即执行。这种方式适用于需要立即响应的场景,例如搜索框输入。

如何取消防抖函数的执行?

某些情况下,我们需要手动取消防抖函数的执行。可以给防抖函数添加一个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,会执行

这种方式为防抖函数提供了一个额外的控制手段,可以在需要的时候阻止函数的执行。

为什么要使用apply而不是直接调用func()?

使用apply可以确保函数在正确的上下文中执行,并传递正确的参数。apply允许我们指定this的值(即上下文)和参数数组。这在处理事件监听器等场景时非常重要,因为我们需要确保函数在触发事件的元素上下文中执行。如果直接调用func(),this的值可能会指向全局对象(例如window),导致错误。

防抖和节流的区别是什么?

防抖和节流都是为了优化性能,减少函数执行频率的技术,但它们的策略不同。

  • 防抖 (Debounce): 在事件被触发后,延迟一段时间执行,如果在这段时间内事件再次被触发,则重新计时。最终只执行最后一次触发。适用于搜索建议、调整窗口大小等场景。
  • 节流 (Throttle): 在一段时间内,只允许函数执行一次。如果在该时间段内事件被多次触发,只有第一次触发会被执行。适用于滚动事件、鼠标移动等场景。

简单来说,防抖是“最后一次有效”,节流是“一段时间内只执行一次”。

防抖函数的常见应用场景有哪些?

  • 搜索建议: 用户在输入框中输入内容时,不需要每次输入都发送请求,而是等待用户停止输入一段时间后,再发送请求获取搜索建议。
  • 调整窗口大小: 在调整窗口大小的过程中,不需要每次调整都重新计算布局,而是等待调整完成后,再重新计算布局。
  • 按钮点击: 防止用户快速多次点击按钮,导致重复提交表单或执行其他操作。
  • 文本编辑器自动保存: 用户编辑文本时,不需要每次修改都保存,而是等待用户停止编辑一段时间后,再自动保存。

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享