js语法---理解防抖原理和实现方法

什么是防抖(节流)

        在实际的网页交互中,如果一个事件高频率的触发,这会占用很多内存资源,但是实际上又并不需要监听触发如此多次这个事件(比如说,在抢有限数量的优惠券时,用户往往会提前在短时间内高频率的点击按钮,但是我只需要接受多次点击中的一次点击,判断有没有抢到即可),这个时候就需要防抖来减少监听的次数,

        防抖就是在多次触发事件时,减少对冗余事件的监听(主要包括,只保留一次监听一定事件内只触发一次监听),

防抖使用场景 :在原有需求能实现的前提下减少多余操作

原理和示例

事件案例

以下是一个点击事件的展示,我们希望判断这个按钮有没有被点击(只要又打印结果即可)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>防抖</title>
</head>
<body>
  <button id="bt">点击</button>
  <script src="index.js"></script>
</body>
</html>
const bt = document.getElementById('bt');
const click = () => {
  console.log('点击了按钮');
}

bt.addEventListener('click', click);

可以看到短时间内用户可能会多次点击按钮,但是我们只需要一次打印就可以判断出用户是否点击了按钮,所以这里有16次的事件冗余。 

设置防抖

思路:在用户多次点击按钮时,我们选择保留最后一次事件触发,即在点击到事件触发这段时间,如果用户再点击,则将上一次点击的操作取消,而等待执行新点击的操作,以此类推;

const bt = document.getElementById('bt');
let timer;// 声明一个全局的定时器变量
const click = () => {
  clearTimeout(timer);// 清除之前的定时器
  timer = setTimeout(() => { // 延时触发操作
    console.log('点击了按钮');
  }, 500);
}

bt.addEventListener('click', click);

         这里的代码要注意这个定时器变量,它要在click函数体外,因为它要在click触发时保存上一次的定时器,并对其实现清楚,如果出现在click函数体内,则会因为每次都产生新的定时器且无法捕获到上一次的定时器,而导致所有打印延迟生效,没有被清楚

此时在点击按钮时,不会立刻打印结果,而多次点击时,由于旧的定时器不断被清楚,打印操作都不会被触发,直到停下点击之后的0.5s才会出现打印结果

封装一个防抖函数

了解了防抖的基本实现,我们封装一个防抖函数以便于对函数的时间间隔防抖功能实现,

防抖函数,它应该接受两个参数,一个是要执行的函数一个是执行函数的间隔,并且返回一个有防抖效果的函数

/**
 * @param fun 要执行的操作
 * @param time 执行的间隔
 * @return 返回有防抖效果的原操作
 * */
const FD = (fun, time) => {
  let timer;// 闭包储存定时器变量
  return function () {
    if (!timer) {
      timer = setInterval(() => {
        fun();
        clearInterval(timer);// 清除定时器
        timer = null;// 重置定时器变量
      }, time);
    }
  }
}

因为要有一个变量来保存定时器的状态,所以这采用闭包的形式保存这个timer,这样每次执行这个FD的返回函数时,timer的值都会保留下来而不是被覆盖,

关于闭包的解释可以参考:js闭包------简单理解闭包含义_js 闭包累加-CSDN博客

使用实例

监听一个页面滚动的事件,打印出滚动的高度,用防抖减少打印的次数

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>防抖</title>
</head>
<body style="height: 200vh;">
  <button id="bt">点击</button>
  <script src="index.js"></script>
</body>
</html>
window.onscroll = () => {
  console.log('滚动的距离', window.scrollY);
}

这里即使是滚动一小段距离也会多次触发打印

滚动了300的距离就触发多次打印,

/**
 * @param fun 要执行的操作
 * @param time 执行的间隔
 * @return 返回有防抖效果的原操作
 * */
const FD = (fun, time) => {
  let timer;// 闭包储存定时器变量
  return function () {
    if (!timer) {
      timer = setInterval(() => {
        fun();
        clearInterval(timer);// 清除定时器
        timer = null;// 重置定时器变量
      }, time);
    }
  }
}

window.onscroll = FD(() => {
  console.log('滚动的距离', window.scrollY);
},500);

有了防抖之后,0.5秒只触发一次打印,大大减少了事件触发

完整代码展示

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>防抖</title>
</head>
<body style="height: 200vh;">
  <button id="bt">点击</button>
  <script src="index.js"></script>
</body>
</html>

index.js: 

// 1.声明一个变量,储存定时器,
// 2.在点击事件中,先清除之前的定时器,再设置新的定时器,
// 3.设置定时器延时操作,相当于等待操作执行结束,才会执行下一次操作(防抖)

const bt = document.getElementById('bt');
let timer;// 声明一个全局的定时器变量
const click = () => {
  clearTimeout(timer);// 清除之前的定时器
  timer = setTimeout(() => { // 延时触发操作
    console.log('点击了按钮');
  }, 500);
}

bt.addEventListener('click', click);

// 多次点击,只执行最后一次操作(节流)


// 节流

/**
 * @param fun 要执行的操作
 * @param time 执行的间隔
 * @return 返回有防抖效果的原操作
 * */
const FD = (fun, time) => {
  let timer;// 闭包储存定时器变量
  return function () {
    if (!timer) {
      timer = setInterval(() => {
        fun();
        clearInterval(timer);// 清除定时器
        timer = null;// 重置定时器变量
      }, time);
    }
  }
}


// window.onscroll = () => {
//   console.log('滚动的距离', window.scrollY);
// }

window.onscroll = FD(() => {
  console.log('滚动的距离', window.scrollY);
},500);

// 滚动时,每隔500ms打印一次滚动的距离

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值