写点什么

网站开发进阶(六十八)防抖节流

  • 2022 年 2 月 24 日
  • 本文字数:1993 字

    阅读完需:约 7 分钟

网站开发进阶(六十八)防抖节流

一、前言 - 为什么要防抖或节流

实现防抖或节流,主要基于以下目的:


  • 及时查询时,减少服务器压力。

  • 频繁执行DOM操作、资源加载等重行为,导致UI停顿甚至浏览器崩溃。

  • 需求是以一定的频率执行后续的处理。

二、防抖 (debounce)

所谓防抖,就是把触发非常频繁的事件合并成一次去执行,以免把一次事件误认为多次。即在指定时间内只执行一次回调函数,如果在指定的时间内又触发了该事件,则回调函数的执行时间会基于此刻重新开始计算,敲键盘就是一个每天都会接触到的防抖操作。


想要了解一个概念,必先了解概念所应用的场景。在 JS 这个世界中,有哪些防抖的场景呢?


  • 登录、发短信等按钮避免用户点击太快,以致于发送多次请求,需要防抖;

  • 调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多,此时需要一次到位,就用到了防抖;

  • 提交表单;

  • 文本编辑器实时保存,当无任何更改操作一秒后进行保存;

  • input 事件(当然也可以用节流,实现实时关键字查找);


实现原理


  • 只要触发,就会清除上一个计时器,又注册新的一个计时器。直到停止触发 wait 时间后,才会执行回调函数。

  • 不断触发事件,就会不断重复这个过程,达到防止目标函数过于频繁调用的目的。


逻辑代码如下,可以看出来「防抖重在清零 clearTimeout(timer)


function debounce(func, wait) {      let timeout;      return function () {        if (timeout) window.clearTimeout(timeout);        timeout = window.setTimeout(function () {          func.apply(this, arguments);        }, wait);      };    }
复制代码

三、节流 (throttle)

节流,顾名思义,控制水的流量。控制事件发生的频率,如控制为 1s 发生一次,甚至 1 分钟发生一次。与服务端(server)及网关(gateway)控制的限流 (Rate Limit) 类似。


  • scroll 事件,每隔一秒计算一次位置信息等;

  • 浏览器播放事件,每隔一秒计算一次进度信息等;

  • input 框实时搜索并发送请求展示下拉列表,每隔一秒发送一次请求 (也可防抖实现);


实现原理


  • 只要触发,只会在当前计时器为空时,注册计时器。

  • 不断触发事件,只会在固定的事件间隔触发。


有 2 种方式实现节流:setTimeout时间戳


setTimeout


function throttle(func, wait) {  let timeout;  return function () {    if (!timeout) {      timeout = window.setTimeout(function () {        func.apply(this, arguments);        timeout = null;      }, wait);    }  };}
复制代码


时间戳


function throttleTime(func, wait) {  let prev = 0;  return function () {    let now = Date.now();    if (now - prev > wait) {      func.apply(this);      prev = now;    }  };}
复制代码


从以上逻辑代码可以看出来「节流重在开关锁 timer=null

四、总结

  • 防抖:防止抖动,单位时间内事件触发会被重置,避免事件误触发多次。

  • 节流:控制流量,单位时间内事件只能触发一次,如果服务器端的限流即 Rate Limit


五、何时使用函数防抖、函数节流

使用函数防抖、函数节流可根据以下需求场景:


  • 当我们只需要处理最后一次触发事件时,用函数防抖。如窗口大小值变化时,并不需要计算中间变化的过程,只需要窗口大小改变完成后的值。

  • 当事件触发过于频繁,我们需要限制事件处理程序的调用频率时,用函数节流

六、示例代码

<!DOCTYPE html><html lang="en">  <head>    <meta charset="UTF-8" />    <meta name="viewport" content="width=<device-width>, initial-scale=1.0" />    <title>Document</title>  </head>  <body>    <button id="bt1">防抖</button>    <button id="bt2">节流</button>  </body>  <script>    // 防抖    function debounce(func, wait) {      let timeout;      return function () {        if (timeout) window.clearTimeout(timeout);        timeout = window.setTimeout(function () {          func.apply(this, arguments);        }, wait);      };    }    // 节流    function throttle(func, wait) {      let timeout;      return function () {        if (!timeout) {          timeout = window.setTimeout(function () {            func.apply(this, arguments);            timeout = null;          }, wait);        }      };    }    function throttleTime(func, wait) {      let prev = 0;      return function () {        let now = Date.now();        if (now - prev > wait) {          func.apply(this);          prev = now;        }      };    }    let bt1 = document.getElementById("bt1");    let bt2 = document.getElementById("bt2");    bt1.onclick = debounce(function () {      console.log(1);    }, 1000);    bt2.onclick = throttleTime(function () {      console.log(2);    }, 1000);  </script></html>
复制代码


发布于: 刚刚阅读数: 3
用户头像

No Silver Bullet 2021.07.09 加入

岂曰无衣 与子同袍

评论

发布
暂无评论
网站开发进阶(六十八)防抖节流