• 理解防抖和节流的区别


    背景:

    在前端开发中,我们会经常需要绑定一些持续触发的事件,如resize, scroll, mousemove等,但是有时候不希望在事件持续触发的过程中太频繁地执行函数

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
      </head>
      <body>
        <div
          id="content"
          style="
            height: 150px;
            line-height: 150px;
            text-align: center;
            color: #fff;
            background-color: #ccc;
            font-size: 80px;
          "
        ></div>
        <script>
          let num = 1;
          const content = document.getElementById("content");
          function count() {
            content.innerHTML = num++;
          }
          content.onmousemove = count;
        </script>
      </body>
    </html>

    在上述代码中,div 元素绑定了 mousemove 事件,当鼠标在 div(灰色)区域中移动的时候会持续地去触发该事件导致频繁执行函数

    解决方案:防抖和节流

    1. 防抖(debounce):是指触发事件后n秒才执行函数,如果在n秒内又触发事件了,则会重新计算函数时间

    (case1:做电梯,电梯会等没人进来了,再等一会,才关闭;case2: input输入框,输入内容搜索,在停下输入过一会后,才发起请求获取匹配的数据;case3: 玩游戏读条,只有读条结束才可以输出,如果读条被打断,要重新读条) 

    1.1 非立即执行版防抖:事件触发后不立即执行,n秒后执行

        <script>
          let num = 1;
          const content = document.getElementById("content");
          function count() {
            content.innerHTML = num++;
          }
    
          //   非立即执行版:触发事件后函数不会立即执行,而是在n秒后执行,
          //   如果n秒内又触发了事件,则会重新计算函数执行时间
          function debounce(func, wait) {
            let timeout;
            return function () {
              const context = this;
              const args = [...arguments];
              if (timeout) {
                clearTimeout(timeout);
              }
              timeout = setTimeout(() => {
                func.apply(context, args);
              }, wait);
            };
          }
          content.onmousemove = debounce(count, 1000);
        </script>

    1.2 立即执行版防抖:触发事件后函数立即执行,n秒内不触发事件才能继续执行

          //   立即执行版: 触发事件后函数会立即执行,然后n秒内不触发事件才能继续执行的效果
          function debounce(func, wait) {
            let timeout;
            return function () {
              const context = this;
              const args = [...arguments];
              if (timeout) {
                clearTimeout(timeout);
              }
              const callNow = !timeout;
              timeout = setTimeout(() => {
                timeout = null;
              }, wait);
              if (callNow) {
                func.apply(context, args);
              }
            };
          }

    1.3 结合版本:实际开发过程中,需要根据不同场景来决定使用哪一个版本的防抖函数。上述版本可以合并:

        
          /**
           * @desc 函数防抖
           * @param func 函数
           * @param wait 延迟执行毫秒数
           * @param immediate true 表立即执行,false 表非立即执行
           */

    function debounce(func, wait, immediate) { let timeout; return function () { const context = this; const args = [...arguments]; if (timeout) { clearTimeout(timeout); } if (immediate) { const callNow = !timeout; timeout = setTimeout(() => { timeout = null; }, wait); if (callNow) { func.apply(context, args); } } else { timeout = setTimeout(() => { func.apply(context, args); }, wait); } }; } content.onmousemove = debounce(count, 1000, false);

    2. 节流(throttle):是指连续触发事件,但是在n秒中只执行一次的函数。节流会稀释函数的执行频率

    (case 1: 看电影,每秒有24帧,意思是每1秒的动画,播放了24张连续的图片;case2: 滚动条加载更多,监听滚动条位置时,设置每1s监听一次,而不是无限次监听;case3: 节流相当于玩游戏某技能的cd,cd时间未到不会执行)

    2.1 时间戳版节流:在持续触发事件的过程中,函数会立即执行,并且每1s执行一次

          function throttle(func, wait) {
            var previous = 0;
            return function () {
              let now = Date.now();
              let context = this;
              let args = arguments;
              if (now - previous > wait) {
                func.apply(context, args);
                previous = now;
              }
            };
          }

    2.2 定时器版节流:在持续触发事件的过程中,函数不会立即执行,每1s执行一次,在停止触发事件后,函数会再执行一次

          function throttle(func, wait) {
            let timeout;
            return function () {
              let context = this;
              let args = arguments;
              if (!timeout) {
                timeout = setTimeout(() => {
                  timeout = null;
                  func.apply(context, args);
                }, wait);
              }
            };
          }

    2.3 时间戳版本节流和定时器节流的区别是,时间戳版本的函数触发是在时间段内开始的时候,而定时器版的函数触发是在时间段内结束的时候。

    两者合并,如下版本:

    /**
     * @desc 函数节流
     * @param func 函数
     * @param wait 延迟执行毫秒数
     * @param type 1 表时间戳版,2 表定时器版
     */
    function throttle(func, wait ,type) {
        if(type===1){
            let previous = 0;
        }else if(type===2){
            let timeout;
        }
        return function() {
            let context = this;
            let args = arguments;
            if(type===1){
                let now = Date.now();
    
                if (now - previous > wait) {
                    func.apply(context, args);
                    previous = now;
                }
            }else if(type===2){
                if (!timeout) {
                    timeout = setTimeout(() => {
                        timeout = null;
                        func.apply(context, args)
                    }, wait)
                }
            }
    
        }
    }

    3. 防抖和节流的区别

    • 用户在搜索的时候,在不停敲字,如果每敲一个字我们就要调一次接口,接口调用太频繁,给卡住了。-----用防抖
    • 用户在阅读文章的时候,我们需要监听用户滚动到了哪个标题,但是每滚动一下就监听,那样会太过频繁从而占内存,如果再加上其他的业务代码,就卡住了。-----用节流

    防抖:结合输入框场景,只有当用户输入完毕一段时间后,才会调用接口,出现联想词

    节流:指定时间间隔,只执行一次任务;应用场景:比如,懒加载监听滚动条的位置,使用节流按一定频率获取

    使用防抖和节流可以减少不必要的损耗(频繁调取接口,网络堵塞,增加服务器压力)。

    最后,汇总

    函数防抖的时候,每次调用事件都是在正常执行暂停后一段时间
    函数节流的时候,则是每隔一定的时间间隔就触发一次
     


    参考:

    https://juejin.cn/post/6844903651278848014

    https://juejin.cn/post/6844904185117278215

    你好,我是Jane,如果万幸对您有用,请帮忙点下推荐,谢谢啦~另外,咱们闪存见哦~
  • 相关阅读:
    四则运算
    屏蔽恶意IP
    Vue企业级优雅实战05-框架开发01-登录界面
    Vue企业级优雅实战04-组件开发01-SVG图标组件
    Vue企业级优雅实战03-准备工作04-全局设置
    Vue企业级优雅实战02-准备工作03-提交 GIT 平台
    802.11ax TWT
    leetcode338
    春招实习面经(已拿阿里/腾讯/亚马逊)
    leetcode weekly contest138
  • 原文地址:https://www.cnblogs.com/jane-panyiyun/p/14680107.html
Copyright © 2020-2023  润新知