前端值得一探究竟特辑 --- 防抖与节流

防抖

防抖函数的作用就是控制函数在一定时间内的执行次数。防抖意味着N秒内函数只会被执行一次,如果N秒内再次被触发,则重新计算延迟时间。
以乘车刷卡的情景举例,只要乘客不断地在刷卡,司机师傅就不能开车,乘客刷卡完毕之后,司机会等待几分钟,确定乘客坐稳再开车。如果司机在最后等待的时间内又有新的乘客上车,那么司机等乘客刷卡完毕之后,还要再等待一会,等待所有乘客坐稳再开车。

1. 防抖的应用

  1. 搜索框输入即查询,如果用户一直在输入中,没有必要不停地调用去请求服务端接口,等用户停止输入的时候,再调用,设置一个合适的时间间隔,有效减轻服务端压力。
  2. 浏览器窗口缩放,resize事件(如窗口停止改变大小之后重新计算布局)等。

2. 防抖的实现

思路:每次触发事件时都取消之前的延时调用方法。

// HTML
  <input id="dom" />
// JS
  var dom = document.getElementById("dom");
  
  dom.addEventListener("input", debounce(() => {
      console.log("假装我是一个请求FUNC");
    }, 1000));
    
  function debounce(fn, wait) {
    var time = null;
    return function () {
      clearTimeout(time);
      time = setTimeout(() => {
        fn.apply(this, arguments)
      }, wait);
    }
  }

陷阱:确保debounce函数的this(上下文还是div)
setTimeout第一个参数使用箭头函数且手动将this绑定到fn上,确保fn的上下文是div,缺一不可,否则的话 this为window和直接 fn()调用是一样的效果,因为他们的this都是window,如果再fn内部要使用事件对象,是获取不到的。

      time = setTimeout(() => {
        console.log(this); //div
        fn.apply(this, arguments)//确保fn函数的this(上下文还是div),所有setTimeOut第一个参数使用箭头函数而不是普通函数,确保this是div,并手动将this绑定到fn上
      }, wait);

3. 详解执行过程

首先,页面加载,代码解析到脚本部分

  1. 函数和变量声明提升
    在这里插入图片描述

  2. 代码自上而下执行

    dom.addEventListener("input", debounce(() => {
          console.log("假装我是一个请求FUNC");
        }, 1000));
    

    这里会调用debounce, 执行环境为debounce开辟一个栈内存,最终addEventListener第二个参数(回调函数)存储的是堆地址H10087。由于回调函数中占用了time、fn、wait,造成了栈内存S10086执行完毕却无法进行内存回收,形成闭包。
    在这里插入图片描述

  3. 事件触发,addEventListener调用回调函数,执行环境为回调函数开辟一个栈内存S1008701,在代码执行过程中,又调用了setTimeOut,环境为setTimeOut开辟一个栈内存S100870101,setTimeOut第一个参数(回调函数)存储的是堆地址H1008702。此时栈内存S10086中wait依旧是1000,随时间递减的是setTimeOut函数内部的形参。
    在这里插入图片描述

  4. 若wait还没有置0,setTimeOut第一个参数(回调函数堆内存H1008702)还没有被触发,事件再次触发,addEventListener再次调用回调函数(堆内存 H10087)。clearTimeout(time);的time是栈内存栈 S10086/ debounce执行中的time,存储着上一轮回调函数执行的setTimeOut手柄。在此上一轮的setTimeOut将被清除,time将存储此轮回调函数执行的setTimeOut手柄。在这里插入图片描述

节流

节流的作用是规定一个单位时间,在这个单位时间内最多只能触发一次函数执行,如果这个单位时间内多次触发函数,只能有一次生效。每次触发事件时都判断当前是否有等待执行的延时函数

1. 节流的应用

  1. 按钮点击事件
  2. 拖拽事件
  3. onScoll
  4. 计算鼠标移动的距离(mousemove)

2. 防抖的实现

每次触发事件时都查询是否有等待执行的延时函数。

// HTML
    <input id="dom" type="button" value="提交" />
// JS
    var dom = document.getElementById("dom");
    var i = 1;
    dom.addEventListener("click", throttle((e) => {
        console.log("假装我是一个请求FUNC");
        console.log(Date());
    }, 1000));
    function throttle(fn, wait) {
        var time = null;
        var previous = 0;
        return function () {
            console.log('节流');
            var now = new Date();
            if (now - previous > wait) {
                fn.apply(this, arguments);
                previous = now;
            }
        }
    }

无论我点击多少次提交,始终限定在1秒内只提交1次。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值