web前端面试–防抖的原理以及实现(附带源码)

导读:本篇文章讲解 web前端面试–防抖的原理以及实现(附带源码),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

web面试题

本人是一个web前端开发工程师,主要是vue框架,整理了一些面试题,今后也会一直更新,有好题目的同学欢迎评论区分享 ;-)

web面试题专栏:点击此处

在这里插入图片描述



场景分析

百度首页的输入框input,是不是随着你的输入而实时更新最新的下拉可选项,这个如果不做防抖,那是不是敲下一个键盘就需要发起一次请求。


防抖的原理

防抖就是单位时间内,如果只有一个操作,时间到了就执行;如果在单位时间内,你又操作了,那就需要重新计时,以保证最后一次操作是使用者本身已经确定完毕的。

就比如上方的input,延迟500毫秒为例子。

你如果500毫秒内,没有再次输入,那是不是意味着,可以向服务器发起请求了;但是但在100毫秒的时候,你又输了一个字符,那是不是意味着,你还没有确定,这个时候又重新开始计时


防抖的实现

这里只做部分代码的抽取,源码在最后面,可运行的HTML文件。

1. 不做防抖的例子

这里不做防抖,方便对比~

// dom
<input id="input1" type="text" />
// js
let input1 = document.getElementById("input1");
input1.addEventListener("input", function (e) {
  // 不能使用箭头函数,避免作用域提升
  console.log("第一个不做防抖的输入框:", this.value);
});

2. 全局timer做防抖的例子

这里用setTimeout来判断是否达到运行时间了,但是用了全局timer来标识。

思考1:如果有多个需求要防抖处理,是不是有好多个timerx变量?要怎么封装才好呢?
思考2:另外,业务跟功能夹杂在一起了,能不能抽取出防抖这个功能呢?

注意:打印事件对象e!!! 闭包不能直接获取到~

// dom
<input id="input2" type="text" />
// js
let input2 = document.getElementById("input2");
let timer = null;
input2.addEventListener("input", function (e) {
  // 如果已经有事件了,则清空计时器重新执行新的,保证是最新一次执行
  if (timer != null) {
    clearTimeout(timer);
  }
  // 这里需要箭头函数,这样就可以提升到input2这个作用域
  timer = setTimeout(() => {
  	console.log(e);
    console.log("全局timer制作的防抖:", this.value);
  }, 1000);
});

3. 闭包做防抖的例子

这个东西比较难理解,不懂的同学可以先看看闭包~
注意1:this的作用域问题,需要用call来处理
注意2:事件e要怎么在闭包中传递

// dom
<input id="input3" type="text" />
// js
let input3 = document.getElementById("input3");
input3.addEventListener(
  "input",
  // 这边新建了一个闭包,返回的是一个函数,保存了改作用域的变量timer
  // 这里的e,不是通过addEventListener调用传入的,是addEventListener调用了闭包,往闭包里面传参了
  // 闭包再通过call传递参数
  debounce(function (e) {
    console.log("e:", e);
    console.log("闭包做的防抖 input3:", this.value);
  }, 1000)
);

/**
  * @author: Penk
  * @description: 防抖,通过闭包保存timer变量
  * @param {*} fn
  * @param {*} timeout
  * @return {*}
  */
 function debounce(fn, timeout) {
   let timer = null;
   return function (e) {
     // 如果已经有事件了,则清空计时器重新执行新的,保证是最新一次执行
     if (timer != null) {
       clearTimeout(timer);
     }
     // 这里需要箭头函数,这样就可以提升到input2这个作用域
     timer = setTimeout(() => {
       fn.call(this);
     }, timeout);
   };
 }

源码

<!--
 * @Author: Penk
 * @LastEditors: Penk
 * @LastEditTime: 2022-11-11 20:15:52
 * @FilePath: \web面试题\防抖.html
 * @email: 492934056@qq.com
-->
<!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>js防抖</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      body {
        padding: 20px;
      }

      .debounceWarper .debounceItem {
        display: flex;
        margin-top: 20px;
      }
      .debounceWarper .debounceItem .debounceItem_label {
        width: 230px;
      }

      .tooltips {
        display: block;
        color: red;
        font-size: 12px;
        margin-top: 2px;
      }
    </style>
  </head>
  <body>
    防抖:防抖就是在单位时间内只执行最后一次操作
    <!-- 防抖:控制高频事件 -->
    <div class="debounceWarper">
      <div class="debounceItem">
        <span class="debounceItem_label">不做防抖的输入框:</span>
        <input class="debounceItem_value" id="input1" type="text" />
      </div>
      <div class="debounceItem">
        <span class="debounceItem_label">全局timer做防抖的输入框:</span>
        <input class="debounceItem_value" id="input2" type="text" />
      </div>
      <span class="tooltips"
        >这里用setTimeout来判断是否达到运行时间了,但是用了全局timer来标识。</span
      >
      <span class="tooltips"
        >思考:1.如果有多个该怎么样,要怎么封装才好呢?</span
      >
      <span class="tooltips"
        >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        2.另外,业务跟功能夹杂在一起了,能不能抽取出防抖这个功能呢?</span
      >

      <div class="debounceItem">
        <span class="debounceItem_label">闭包做防抖的输入框:</span>
        <input class="debounceItem_value" id="input3" type="text" />
      </div>
      <div class="debounceItem">
        <span class="debounceItem_label">闭包做防抖的输入框:</span>
        <input class="debounceItem_value" id="input4" type="text" />
      </div>
    </div>

    <script>
      // -----------------------不做防抖的输入框:---------------------- //
      let input1 = document.getElementById("input1");
      input1.addEventListener("input", function (e) {
        // 不能使用箭头函数,避免作用域提升
        console.log("第一个不做防抖的输入框:", this.value);
      });

      // -----------------------全局timer做防抖的输入框:---------------------- //
      let input2 = document.getElementById("input2");
      let timer = null;
      input2.addEventListener("input", function (e) {
        // 如果已经有事件了,则清空计时器重新执行新的,保证是最新一次执行
        if (timer != null) {
          clearTimeout(timer);
        }
        // 这里需要箭头函数,这样就可以提升到input2这个作用域
        timer = setTimeout(() => {
          console.log("e:", e);
          console.log("全局timer制作的防抖:", this.value);
        }, 1000);
      });

      // -----------------------闭包做防抖的输入框:---------------------- //
      let input3 = document.getElementById("input3");
      input3.addEventListener(
        "input",
        // 这边新建了一个闭包
        debounce(function (e) {
          console.log("e:", e);
          console.log("闭包做的防抖 input3:", this.value);
        }, 1000)
      );

      let input4 = document.getElementById("input4");
      input4.addEventListener(
        "input",
        // 这边新建了另外一个闭包
        debounce(function (e) {
          // console.log("e:", e);
          console.log("闭包做的防抖 input4:", this, this.value);
        }, 1000)
      );

      /**
       * @author: Penk
       * @description: 防抖,通过闭包保存timer变量
       * @param {*} fn
       * @param {*} timeout
       * @return {*}
       */
      function debounce(fn, timeout) {
        let timer = null;
        return function (e) {
          // 如果已经有事件了,则清空计时器重新执行新的,保证是最新一次执行
          if (timer != null) {
            clearTimeout(timer);
          }
          // 这里需要箭头函数,这样就可以提升到input2这个作用域
          timer = setTimeout(() => {
            fn.call(this,e);
          }, timeout);
        };
      }
    </script>
  </body>
</html>

源码页面展示图

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/66362.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!