jsliang 求职系列 – 12 – 手写防抖和节流

时间:2021-1-8 作者:admin

面试一面大概率问题:

  1. 什么是防抖,如何防抖?
  2. 什么是节流,如何节流?

一 目录

不折腾的前端,和咸鱼有什么区别

目录
一 目录
二 防抖
 2.1 手写防抖
 2.2 防抖应用
三 节流
 3.1 手写节流
 3.2 节流应用
四 防抖 + 节流

二 防抖

返回目录

防抖:任务频繁触发的情况下,只有任务触发的间隔超过指定间隔的时候,任务才会执行。

举例:

  1. 监听拖拽滚动条,然后频繁向下滚动信息,会变得很慢,很迟钝。
  2. 点击提交表单后,用户在结果还没出来的时候重复触发。

简单来说:某件事你并不想它太过频繁触发,那么设置一个定时器,每次进来的时候都清除原本的定时器,然后重新开始计时。

2.1 手写防抖

返回目录

  1. 设置定时器
  2. 设置一个闭包,返回一个方法
  3. 如果反复进来,清空前面的定时器,再重新设置一遍
function debounce(fn) {
  let timer = null;
  return function() {
    clearTimeout(timer);

    timer = setTimeout(() => {
      fn.call(this.arguments);
    }, 1000);
  }
}

2.2 防抖应用

返回目录

结合实例:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>防抖</title>
</head>
<body>
  <button id="debounce">点我防抖!</button>

  <script>
    window.onload = function() {
      // 1、获取这个按钮,并绑定事件
      var myDebounce = document.getElementById("debounce");
      myDebounce.addEventListener("click", debounce(sayDebounce));
    }

    // 2、防抖功能函数,接受传参
    function debounce(fn) {
      // 4、创建一个标记用来存放定时器的返回值
      let timeout = null;
      return function() {
        // 5、每次当用户点击/输入的时候,把前一个定时器清除
        clearTimeout(timeout);
        // 6、然后创建一个新的 setTimeout,
        // 这样就能保证点击按钮后的 1000 毫秒间隔内
        // 如果用户还点击了的话,就不会执行 fn 函数
        timeout = setTimeout(() => {
          fn.call(this, arguments); // 修正 this 指向问题
        }, 1000);
      };
    }

    // 3、需要进行防抖的事件处理
    function sayDebounce() {
      console.log(this);
      // ... 有些需要防抖的工作,在这里执行
      console.log("防抖成功!");
    }

  </script>
</body>
</html>

三 节流

返回目录

节流:指定时间间隔内只会执行一次任务。

举例:

  1. 你不想频繁为你女票买单,于是约好每月 1 号清空购物车
  2. 防止过快拖动滚动条,导致 JS 跟不上拖动频率,通过节流限制每秒触发监听的次数(固定时间固定频率)

简单来说:年轻人要保持一日三餐,规律作息,那就通过节流来限制。

3.1 手写节流

返回目录

  1. 设置一个标记
  2. 设置一个闭包,返回一个方法
  3. 如果重复进去的时候,标记已经动了,那就组织程序进一步运行
  4. 如果定时器执行完了,设置这个标记为没动,允许下一次执行
function throttle(fn) {
  let timer = true;
  return function() {
    if (!timer) {
      return;
    }
    timer = false;
    setTimeout(() => {
      fn.call(this, arguments);
      timer = true;
    }, 1000);
  }
}

3.2 节流应用

返回目录

结合实例:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>节流</title>
</head>
<body>

  <button id="throttle">点我节流!</button>

  <script>
    window.onload = function() {
      // 1、获取按钮,绑定点击事件
      var myThrottle = document.getElementById("throttle");
      myThrottle.addEventListener("click", throttle(sayThrottle));
    }

    // 2、节流函数体
    function throttle(fn) {
      // 4、通过闭包保存一个标记
      let canRun = true;
      return function() {
        // 5、在函数开头判断标志是否为 true,不为 true 则中断函数
        if(!canRun) {
          return;
        }
        // 6、将 canRun 设置为 false,防止执行之前再被执行
        canRun = false;
        // 7、定时器
        setTimeout( () => {
          fn.call(this, arguments);
          // 8、执行完事件(比如调用完接口)之后,重新将这个标志设置为 true
          canRun = true;
        }, 1000);
      };
    }

    // 3、需要节流的事件
    function sayThrottle() {
      console.log("节流成功!");
    }

  </script>
</body>
</html>

四 防抖 + 节流

返回目录

防抖有时候因为触发太过频繁,导致一次响应都没有。

所以希望固定的时间必定给用户一个响应,于是就有了防抖 + 节流的操作。

  1. 设置 last 记录定时器开始的时间
  2. 设置 timer 表示一个定时器
  3. 获取当前时间 now
  4. 如果当前时间 – 开始时间小于延迟时间,那么就防抖
  5. 否则设置时间到了,执行函数
function throttle(fn, delay) {
  let last = 0, timer = null;
  return function (...args) {
    let now = new Date();
    if (now - last < delay){
      clearTimeout(timer);
      setTimeout(function() {
        last = now;
        fn.apply(this, args);
      }, delay);
    } else {
      // 这个时候表示时间到了,必须给响应
      last = now;
      fn.apply(this, args);
    }
  }
}

jsliang 的文档库由 梁峻荣 采用 知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议 进行许可。
基于 github.com/LiangJunron… 上的作品创作。
本许可协议授权之外的使用权限可以从 creativecommons.org/licenses/by… 处获得。

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。