防抖和节流

Yaurora

防抖和节流,是当频繁触发某个事件时,对其做出相关限制。在在后端开发中,使用防抖和节流,可以减少向服务器请求的频率

概念

防抖: 延迟执行。 n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时

节流: 固定时间内执行。n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效

效果示意图

test

实现

未实现防抖和节流

  1. 定义两个页面元素
1
2
<input type='text' class=input />
<h2 class='result'>
  1. 监听元素输入事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const inputEl = document.querySelector('.input')
const resultEl = document.querySelector('.result')

async function getRemoteData(){
const text = this.value
// 模拟网络请求
const result = await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(text)
}, 500)
})

resultEl.innerHTML = `输入内容为: ${result}`
}

inputEl.addEventListener('input', getRemoteData)

防抖

使用setTimeout和clearTimeout实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 定义防抖函数
function debouce(event, await){
let timer = null
return function(...args) {
// 每次触发后,判断是否已经有了定时器, 如果有,清除
if (timer) clearTimeout(timer)
// 如果没有,定义一个定时器, await事件后执行
timer = setTimeout(() => {
event.apply(this, args)
}, await)
}
}

// 重新绑定input事件
inputEl.addEventListener('input', debouce(getRemoteData, 1000))

节流

时间戳的方式
1
2
3
4
5
6
7
8
9
10
11
12
13
function throttle(event, await) {
let pre = 0
return function(...args) {
// 判断和上一次执行时间的间隔是否大于await
if (new Date() - pre > await){
pre = new Date()
event.apply(this, args)
}
}
}
// 使用这种方式,有一个弊端,就是最后一次事件,可能不会执行(当n和n-1的时间间隔大于await才会执行)

inputEl.addEventListener('input', throttle(getRemoteData, 1000))
定时器的方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function throttle(event, await) {
let timer = null
return function(...args) {
if (!timer) {
timer = setTimeout(() => {
timer = null //执行完成后,需要将变量重置,然后重新生成新的定时器
event.apply(this, args)
}, await)
}
}
}

// 使用这种方式,就是第一次事件触发后不会立即执行, 不过问题也不大
inputEl.addEventListener('input', throttle(getRemoteData, 1000))
时间戳和定时器结合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function throttle(event, await) {
let pre = 0, timer = null
return function(...args) {
if (new Date() - pre > await) {
// 这里判断一下的逻辑是, 上一次(定时器)和现在(时间戳)的方式需要转换,清除上一次的变量,或者说替换上一次的执行
if (timer) {
clearTimeout(timer)
timer = null
}
event.apply(this, args)
} else {
timer = setTimeout(() => {
event.apply(this, args)
}, await)
}
}
}

使用三方库

lodash使用

​ 可以通过npm下载管理,

​ 我这里就直接使用cdn方式

1
2
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>

  • _.debounce(func, wait, option)

    1
    inputEl.addEventListener('input', _.debounce(getRemoteData, 1000))
  • _.throttle(func, wait, option)

    1
    inputEl.addEventListener('input', _.throttle(getRemoteData, 1000))

应用场景

防抖在连续的事件,只需触发一次回调的场景有:

  • 搜索框搜索输入。只需用户最后一次输入完,再发送请求
  • 手机号、邮箱验证输入检测
  • 窗口大小resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。

节流在间隔一段时间执行一次回调的场景有:

  • 滚动加载,加载更多或滚到底部监听
  • 搜索框,搜索联想功能
  • 标题: 防抖和节流
  • 作者: Yaurora
  • 创建于 : 2023-03-09 11:01:29
  • 更新于 : 2023-03-10 18:47:10
  • 链接: https://jingyu.life/2023/03/09/node/debounce-throttle/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。