防抖和节流的应用场景和实现

本文深入解析防抖和节流技术,旨在减少不必要的计算,避免资源浪费。通过实例演示如何在用户输入和事件监听中应用,提供高效执行代码的策略。

防抖

防抖就是将一段时间内连续的多次触发转化为一次触发。

使用场景

一般可以使用在用户输入停止一段时间过后再去获取数据,而不是每次输入都去获取,如下图:

实现代码

  function debounce<Return>(
    fn: (...params: any[]) => Return, 
    wait: number, /** 等待时间 */
    immediate: boolean /** 是否立刻执行一次 */
  ): Executor<Return> {
    const now: () => number = Date.now.bind(Date);
    let lastTime: number = 0;
    let timer: number = null;
    let params: IArguments = null;
    let _this: Function | null = null;

    function later(): void {
      const nowTime: number = now();

      if (nowTime - lastTime < wait) {
        // 如果还不够等待时间则继续等待
        const remainTime = wait - (nowTime - lastTime);

        timer = setTimeout(later, remainTime);
      } else {
        // 已到等待时间,执行回调
        debouncer.result = fn.apply(_this, params);

        timer = null;
        _this = null;
        params = null;
      }
    }

    function execute(): (Return | null) {
      lastTime = now();
      _this = this;
      params = arguments;

      try {
        if (immediate && timer === null) {
          // 立刻执行一次
          debouncer.result = fn.apply(_this, params);
        }

        return debouncer.result;
      } finally {
        if (timer === null) {
          // 加入时间队列,等待执行
          timer = setTimeout(later, wait);
        }
      }
    }

    // 创建执行器
    const debouncer: Executor<Return> = {
      execute,
      result: null,
    };

    return debouncer;
  };

原理很简单,主要是判断是否到达等待时间,如果没到达的话就继续加入任务队列等待执行。使用方法:

import utils from '../index';

const input = document.querySelector('input');
const executor = utils.fn.debounce(function(value) {
  console.log('fetch');
  
  return value;
}, 300);

let value = null;

input.addEventListener('input', function(e) {
  executor.execute(e.target.value);
  value = executor.result;
});

返回一个执行器的原因是这样可以方便获取最后一次函数执行时返回的值。

节流

节流顾名思义则是将减少一段时间内触发的频率。

使用场景

可以将一些事件降低触发频率。比如懒加载时要监听计算滚动条的位置,但不必每次滑动都触发,可以降低计算的频率,而不必去浪费资源;另外还有做商品预览图的放大镜效果时,不必每次鼠标移动都计算位置。

实现代码

throttle: function <Return>(
    fn: (...params: any[]) => Return,
    wait: number,
    {
      isExecuteAtStart = true,
      isExecuteAtEnd = true,
    }: ThrottleOptions = {
      isExecuteAtStart: true,
      isExecuteAtEnd: true,
    }
  ): Executor<Return> {
    let timer: number = null;
    let _this: Function = null;
    let params: IArguments = null;

    function execute(): (Return | null) {
      _this = this;
      params = arguments;

      if (isExecuteAtStart && timer === null) {
        // 如果需要开始的时候执行且没有计时器
        executor.result = fn.apply(_this, params);
        _this = null;
        params = null;
      }

      if (isExecuteAtEnd) {
        // 如果结束的时候需要执行
        if (timer === null) {
          timer = setTimeout(function () {
            executor.result = fn.apply(_this, params);
            _this = null;
            params = null;
            timer = null;
          }, wait);
        }
      }

      return executor.result;
    }

    const executor: Executor<Return> = {
      execute,
      result: null
    };

    return executor;
}

最后

防抖和节流的目的都是为了减少不必要的计算,不浪费资源,只在适合的时候再进行触发计算。源码可以在这个项目里的fn模块看到,另外还有许多实用的功能,欢迎使用和学习。如果我的文章对你有些帮助的话,可以点个赞,谢谢~

### 防抖节流的具体应用场景实现方式 #### 应用场景 防抖(Debounce)节流(Throttle)是前端开发中常用的两种优化技术,主要用于减少高频事件触发带来的性能开销。 - **防抖应用场景** 防抖适用于那些只需要在最后一次操作完成后才执行的操作。例如,在搜索框中输入文字时,如果每次按键都发送请求,则会浪费大量网络资源。通过防抖可以确保只有当用户停止输入一段时间后再发起请求[^2]。其他常见场景包括: - 窗口调整大小(`resize`),防止频繁计算布局。 - 表单提交按钮点击,避免多次重复提交。 - 滚动到底部加载更多数据的功能,等待滚动完全结束后再触发加载逻辑。 - **节流应用场景** 节流适合于需要定期执行某些操作的场景,即使事件触发频率很高也只允许每隔一定时间执行一次。典型例子有: - 鼠标移动跟踪效果,比如拖拽元素或鼠标悬停提示气泡显示。 - 页面无限滚动加载新内容,控制每秒最多刷新几次视图。 - 游戏中的帧率限制,保持稳定的动画更新速率而不至于过载设备硬件能力[^3]。 #### 实现方式 以下是基于 JavaScript 的简单实现方法: ##### 防抖函数 ```javascript function debounce(func, wait) { let timeout; return function(...args) { const context = this; clearTimeout(timeout); timeout = setTimeout(() => func.apply(context, args), wait); }; } ``` 这段代码定义了一个通用的防抖工具函数 `debounce` ,它接受两个参数:要延迟执行的目标函数 `func` 等待毫秒数 `wait` 。每当调用返回的新函数时都会重置计时器;一旦超过指定的时间间隔而没有任何新的调用发生,就会最终调用原始目标函数[^4]。 ##### 节流函数 ```javascript function throttle(func, limit) { let inThrottle; return function() { const args = arguments; const context = this; if (!inThrottle) { func.apply(context, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; } ``` 此版本展示了如何创建一个基本形式的节流机制。这里的关键在于引入布尔变量 `inThrottle` 来标记当前是否处于冷却期之中。只要该标志位为假就立即运行传入的方法并设定一个新的超时期限来阻止后续连续调用直到结束为止[^3]。 #### 主要区别 | 特性 | 防抖 | 节流 | |--------------|-------------------------------|------------------------------| | 定义 | 延迟到一系列动作完成之后再行动 | 控制单位时间内仅能有一次有效行为 | | 执行时机 | 只会在最后的一次触发后生效 | 即使有多次触发也会按固定周期分批处理 | | 使用场合示例 | 输入框自动补全、表单验证 | 鼠标滑轮监听、键盘按下状态监控 | 总结来说,两者虽然都是为了应对高频率事件所设计出来的解决方案,但在具体适用范围上有明显差异——前者更关注的是“静止后的反应”,后者则是关于“持续过程里的节奏把控”。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值