防抖和节流

什么是防抖(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. 搜索框的搜索联想功能
相关推荐
Darling噜啦啦11 小时前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
swipe12 小时前
正则表达式入门到进阶:从表单校验到手写模板引擎
前端·javascript·面试
神奇小汤圆13 小时前
RAG大厂面试题汇总:向量检索、混合检索、Rerank、幻觉处理高频问题
面试
假如让我当三天老蒯15 小时前
回归基本功:Map/Set 与 WeakMap/WeakSet 的区别
前端·面试
假如让我当三天老蒯18 小时前
回归基本功!前端的解构赋值、扩展运算符、剩余参数
前端·面试
Lee川19 小时前
Memory 模块深度解析(面试向)
人工智能·面试
JAVA9652 天前
JAVA面试-JVM篇 03-JVM运行时数据区哪些是线程私有的哪些是共享的
java·jvm·面试
枫子有风2 天前
LLM-Agent智能体(大厂面试常问)
面试·职场和发展·llm·agent
Oo_行者_oO2 天前
删库先别跑路,万一修复呢?MySQL 误删数据恢复可落地运维文档
数据库·面试
Moment2 天前
从多人编辑到 Agent 写文档,Hocuspocus v4 正在改写协同系统 😍😍😍
前端·后端·面试