防抖和节流

什么是防抖(Debounce)?

短时间内连续触发多次事件(用户点击/鼠标移动/键盘事件/鼠标滚轮等),只执行最后一次, 在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。

javascript 复制代码
      var btn = document.getElementById("btn");
      btn.onclick = debounce(() => {
        console.log("防抖执行了");
      }, 1000);
      
      //封装防抖函数(debounce)
      function debounce(fn, wait) {
        let timer = null;
        return function () {
          let _this = this;
          let args = arguments;
          // 每次点击时都是先关在开,永远保证当前只有一个正在执行的定时器
          if (timer) {
            clearTimeout(timer);
          }
          timer = setTimeout(function () {
            fn.apply(_this, args);
          }, wait);
          console.log(timer); 
        };
      }

下图是控制台的输出情况:

可以发现,只有当用户停止点击后,才会触发fn()函数,打印"防抖执行了"语句,每次产生新的触发,都会覆盖旧有触发的定时器,并重新计时,即多次点击只有计最后一次有效

什么是节流(Throttle)?

在一个单位时间内,连续多次事件触发,只执行第一次。短时间内连续触发多次事件,会减少执行次数。达到稀释函数执行频率的效果。 可以将节流函数看作一个闸门,一旦有事件触发,就立即关闭闸门,不让其他事件进入,直到进入的事件响应结束,才再次开放闸门。

1.用定时器实现:

javascript 复制代码
      var btn = document.getElementById("btn"); 
      btn.onclick = throttle(() => { console.log("节流函数执行"); }, 1000);
      
      function throttle(fn, wait) {
        let timer = null;
        return function () {
          let _this = this;
          let _args = arguments;

          if (!timer) {   //若当前没有正在执行的定时器
            timer = setTimeout(function () {
              timer = null;
              fn.apply(_this, _args);
            }, wait); //只有当定时器将wait时间走完,timer才会再次被赋值null,才可再次进入if语句
          }
          console.log(timer);
        };
      }

2.用时间戳实现

javascript 复制代码
     function throttle1(fn, wait) {
        let time = 0;
        return function () {
          let _this = this;
          let _args = arguments;
          
          let now = Date.now();
          //相邻两次点击的时间间隔大于需要wait的时间,即上一单位时间内事件已响应完毕
          if (now - time > wait) { 
            fn.apply(_this, _args);
            time = now;
          }
        };

下图是控制台的输出情况:

可以发现,与防抖函数不同,当用户多次点击时,实际响应的始终是第一次点击时的定时器。只至定时器将需要wait的时间走完,打印了"节流函数执行"。即单位时间内,多次触发仅执行第一次。

防抖和节流的异同

相同点:

  1. 作用都是为了降低回调函数触发频率,减小计算负担。
  2. 都是基于一次性定时器setTimeout实现的,并运用闭包进行封装。

区别:

防抖函数多次触发只执行最后一次,节流函数多次触发只执行第一次。

触发频率不同,实际上防抖函数比节流函数更为"严格",防抖在单位时间s内永远只执行最后一次,而节流函数函数则可执行s/wait(向下取整)次。

例如,防抖和节流函数定时器的wait时间均为500ms,那么在5s内,防抖函数仅触发最后一次,而节流函数将触发10次。

防抖和节流的使用场景

防抖(适合仅需一次生效的场景)

  1. 登录,发送验证码,限时秒杀等按钮,用户短时间内多次点击,仅最后一次响应并发送请求
  2. search搜索时,等待用户结束输入后,再发送请求。
  3. windows触发resize时,会频繁进行计算调整窗口大小,用防抖节约计算资源。

节流(适合隔一段时间执行一次场景)

  1. 滚动监听,例如下拉加载,触底加载等
  2. 搜索框的搜索联想功能
相关推荐
David猪大卫9 小时前
【C++修炼】智能指针使用及原理
开发语言·c++·经验分享·笔记·学习·考研·面试
后台模板学习12 小时前
2026最新面试真题:到达用英语怎么说背后的逻辑与源码剖析
面试·职场和发展·php
Thomas214313 小时前
mysql 索引面试复习
数据库·mysql·面试
CoderYanger13 小时前
前端基础——JavaScript(WebAPI)(下篇)
java·开发语言·前端·javascript·程序人生·面试·职场和发展
ocean210315 小时前
2025-2026年嵌入式开发大厂面试高频问题
面试·秋招·嵌入式开发·rtos·面经·嵌入式面试
敲代码的嘎仔15 小时前
自己设计了一个兑换码算法:自增ID + Base32转码 + 按位加权签名 + 异或混淆,面试被追问细节时终于不用慌了
java·数据库·mysql·算法·微服务·面试·职场和发展
江湖十年19 小时前
Go 还是 Golang?可能你一直都搞错了!
后端·面试·go
ClouGence20 小时前
秋招省力指北:分享一下我用 AI 辅助秋招的流程
面试·求职
Moment21 小时前
为什么市面上的 coding agent 大多数都基于Nodejs?
前端·后端·面试
蒸蒸yyyyzwd21 小时前
面经学习笔记
c++·面试·八股