防抖与节流

👉 点击进入传送阵,前往 Demo 页面。

本文讲解了关于函数防抖、节流的相关内容,希望能帮助同学们掌握更多的知识。

本文所涉及的知识点:

  1. 闭包
  2. 高阶函数

函数防抖 debounce

概念定义

任务频繁触发的情况下,只有当任务稳定之后(一定时间内没有再次触发),任务才会执行。

应用场景

获取用户输入、实时筛选与搜索、向服务器发送请求等。

工作原理

  1. 设置一个 timer 变量,用于记录当前执行的防抖 setTimeout
  2. 当触发防抖函数时,首先清除上一个执行中的 setTimeout
  3. 随后创建一个新的 setTimeout,并将延迟设置为防抖间隔 wait
  4. setTimeout 没有在防抖间隔 wait 内清除时,即成功执行。

示例代码

/**
 * 防抖函数
 *
 * @param {Function} fn 要防抖的函数
 * @param {number} wait 防抖间隔,即多久没有抖动后才执行函数
 */
function debounce(fn, wait = 300) {
  /** 定时器,用于记录将要执行的任务 */
  let timer = -1;
  return (...args) => {
    // 清除上一个记录的定时器
    // 如果 间隔时间 < wait,上一个计时器会在执行前被清除
    // 即实现防抖
    clearTimeout(timer);
    timer = setTimeout(() => fn.call(this, ...args), wait);
  };
}

实际应用

我们来解析一下 Demo 页面 中函数防抖的实际应用。

这是一个典型的防抖函数应用场景,获取用户输入。

<!-- https://gist.github.com/DevinDon/7ceebcc1e11921709731026fa5f6f0da#file-index-html-L62 -->
<!-- line: 62 -->
<input oninput="inputWithDebounce(event)" />

<!-- 展示结果的组件 -->
<input id="display-debounce" disabled />

调用代码如下:

// debounce 函数与示例代码相同
function debounce(fn, interval = 300) {
  let timer = -1;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn.call(this, ...args), interval);
  };
}
// 将输入框的值传入展示结果的组件内 #display-debounce
const input = event => document.getElementById('display-debounce').value = event.target.value;
// 在用户停止输入 1000ms 后,触发 input 函数
const inputWithDebounce = debounce(input, 1000);

查看 Demo 页面可以帮助你理解这段代码。


函数节流 Throttle

概念定义

在触发状态,指定时间间隔内只执行一次任务。

应用场景

检测鼠标位置、拖拽组件、与后端服务器通信刷新数据等。

工作原理

  1. 设定一个 runnable 变量,表明当前是否在可执行(非节流)状态;
  2. 如果是节流状态 runnable = false,那么函数被触发时会直接返回,取消执行;
  3. 如果是非节流状态 runnable = true,那么函数被触发时会将 runnable 设置为 false,即节流状态;
  4. 随后设置一个延迟函数,在节流延迟之后将 runnable 设置为 true,即非节流状态;
  5. 最后执行目标函数。

示例代码

/**
 * 节流函数
 *
 * @param {Function} fn 要节流的函数
 * @param {number} delay 节流延迟,即有事件触发时,每隔多长时间执行一次函数
 */
function throttle(fn, delay = 300) {
  /** 可运行(非节流)状态 */
  let runnable = true;
  return (...args) => {
    // 如果处于不可运行(节流)状态,那么取消本次执行
    if (!runnable) { return; }
    // 如果可运行,重置为不可运行(节流)状态
    runnable = false;
    // 在 delay 重置为可运行(非节流)状态
    setTimeout(() => runnable = true, delay);
    return fn.call(this, ...args);
  };
}

实际应用

我们来解析一下 Demo 页面 中函数节流的实际应用。

这是一个常用于拖拽组件的应用场景,获取鼠标位置。

调用代码如下:

// throttle 函数与示例函数相同
function throttle(fn, delay = 300) {
  let runnable = true;
  return (...args) => {
    if (!runnable) { return; }
    runnable = false;
    setTimeout(() => runnable = true, delay);
    return fn.call(this, ...args);
  };
}

// 在结果区域 #display-throttle 输出当前鼠标位置
const mouse = event => document.getElementById('display-throttle').value = `${event.screenX}, ${event.screenY}`;
// 当鼠标在移动状态时,每隔 1000ms 更新一次鼠标坐标信息
const mouseWithThrottle = throttle(mouse, 1000);

查看 Demo 页面可以帮助你理解这段代码。


如果觉得本文不错,不妨在 Github 点个 ✨star~

IInfinity

IInfinity

大道虽简,知易行难。
CN