zoukankan      html  css  js  c++  java
  • 564 函数的防抖和节流

    • 函数的防抖和节流
    • 防抖:在用户频繁触发的时候,只识别一次(识别第一次/识别最后一次)
    • 节流: 目的是频繁触发中缩减频率。假设我们频率设置为500ms,我们频繁触发了10000ms,对于防抖,则只触发一次;对于节流,则触发20次

    // 第一次点击,没有立即执行,等待500MS,看看这个时间内有没有触发第二次,有触发第二次,说明在频繁点击,不去执行我们的事情(继续看第三次和第二次间隔...);如果没有触发第二次,则认为非频繁点击,此时去触发;

    /*

    • debounce:实现函数的防抖(目的是频繁触发中只执行一次)
    • @params
    • func:需要执行的函数
    • wait:检测防抖的间隔频率
    • immediate:是否是立即执行(如果为true是控制第一次触发的时候就执行函数,默认FALSE是以最后一次触发为准)
    • @return
    • 可被调用执行的函数
      */

    /*
    防抖:我的注释
    1、在指定时间内,触发第二次,清除上一次的操作(定时器),重新计时,生成新的操作;触发第三次,清除上一次的操作,重新计时,生成新的操作,以此类推。超过指定时间,则执行操作。
    总之,频繁操作,即在指定时间内,操作2次及2次以上,就清空上一次的操作,重新计时,生成新的操作。
    2、防抖,不是每间隔指定时间,都执行一次,而是指定一个间隔时间,在间隔时间内,有木有触发2次,只要触发2次,就是频繁的,就以第一次或最后一次为主
    */


    防抖的应用场景

    • 输入框中频繁的输入内容,搜索或者提交信息;
    • 频繁的点击按钮,触发某个事件;
    • 监听浏览器滚动事件,完成某些特定操作;
    • 用户缩放浏览器的resize事件;

    总之,密集的事件触发,我们只希望触发比较靠后发生的事件,就可以使用防抖函数。


    节流的应用场景

    • 监听页面的滚动事件;
    • 鼠标移动事件;
    • 用户频繁点击按钮操作;
    • 游戏中的一些设计;

    总之,依然是密集的事件触发,但是这次密集事件触发的过程,不会等待最后一次才进行函数调用,而是会按照一定的频率进行调用。


    <!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="btn">按钮</button>
    </body>
    
    </html>
    <script>
      // 【这里,debounce中的this指向window】
      function debounce(func, wait = 500, immediate = false) {
        let timer = null;
        // anonymous、setTimeout的this都是指向btn
        return function anonymous(...params) {
          // 第一次触发 或 立即执行的条件:immediate为true,timer为null
          let now = immediate && !timer;
          clearTimeout(timer);
          timer = setTimeout(() => {
            timer = null;
            // 执行函数:注意保持this和参数的完整度,让定时器的this和anonymous保持一致 
            // 【this指向事件源,箭头函数没有自己的this】
            !immediate ? func.call(this, ...params) : null;
          }, wait);
    
          // 用于第一次触发 或 立即执行 
          now ? func.call(this, ...params) : null;
        };
      }
    
    
      // -----------------------------------------------------
    
    
      /*
       * 假设我们频率设置为500ms,我们频繁触发了10000ms,对于防抖,则只触发一次;对于节流,则触发20次
       * 
       * throttle:实现函数的节流(目的是频繁触发中缩减频率)
       *   @params
       *      func:需要执行的函数
       *      wait:自己设定的间隔时间(频率)
       *   @return
       *      可被调用执行的函数
       */
      // 【第一次触发时,remaining是负数,previous被赋值为当前时间。】
      // 【第二次触发,假设是在间隔20ms,则remaining = 500 - (新的当前时间 - 上一次触发时间) = 500 - 20 = 480,也就是定时器的等待时间remaining。】
      function throttle(func, wait = 500) {
        let timer = null;
        let previous = 0; // 记录上一次操作时间
        return function anonymous(...params) {
          let now = new Date(); // 当前操作的时间
          let remaining = wait - (now - previous); // 剩余时间
          // remaining <= 0 与 remaining > 0 的区别:后者多了个定时器,previous不一样
          if (remaining <= 0) {
            // 两次间隔时间超过频率:把方法执行即可
            // clearTimeout是从系统中清楚定时器,timer值不会变为null 【银行系统清理排队号】
            clearTimeout(timer);
            // 这是给变量timer赋值为null,就可以通过timer是否为null,判断有木有定时器 【自己把小纸条丢垃圾篓,也可以不扔,拿手里,但是就不能通过timer是否为null,判断有木有定时器了。】
            timer = null;
            previous = now; // 【把上一次操作时间修改为当前时间】
            func.call(this, ...params);
          } else if (!timer) {
            // 两次间隔时间小于频率,如果没有定时器,设置定时器;有定时器了,就不用重新设置定时器,而是以上一次的计时为准
            // 两次间隔时间没有超过频率,说明还没有达到触发标准,设置定时器等待即可(还差多久,就等多久) 【假设时间间隔是500ms,第20ms点击,剩余480ms,就等待480ms。】
            timer = setTimeout(() => {
              clearTimeout(timer);
              timer = null;
              // 过了remaining时间后,才去执行func,所以previous不能等于now
              previous = new Date(); // 【把上一次操作时间修改为当前时间】
              func.call(this, ...params);
            }, remaining);
          }
        };
      }
    
      function func() {
        console.log('OK');
      }
    
      // debounce中的this指向window,因为调用debounce,前面没有任何东西。注意,这里是调用函数,而不是定义函数,如果是定义函数,那么debounce中的this指向btn
      // btn.onclick = debounce(func, 500, true);
      // btn.onclick = func;
      btn.onclick = throttle(func, 1000);
    
    
      // -------------------------------------------
    
    
      //  防止频繁点击触发:设置标识进行判断 
      let isClick = false;
      btn.onclick = function () {
        // isClick为false,则不继续往下执行
        if (isClick) return;
        isClick = true;
        setTimeout(() => {
          console.log('OK');
          isClick = false;
        }, 500);
      };
    </script>
    
  • 相关阅读:
    springMVC入门
    【终极指南】图文详解Chrome插件离线安装方法
    IDM下载器使用方法详解:百度网盘下载,视频会员一网打尽!
    Mac下复制粘贴的快捷键是什么?随记
    华为手机维修点查询终于上线了
    如何将已经安装从chrome扩展程序导出备份为.CRX文件?
    Chrome浏览器 v68.0.3440.106 正式版怎么样?
    Postman插件如何安装
    分享一款非常好用的Fatkun图片批量下载工具
    上海苹果维修点分享苹果电脑MACBOOK故障维修常见案例
  • 原文地址:https://www.cnblogs.com/jianjie/p/13872633.html
Copyright © 2011-2022 走看看