函数防抖和节流

什么是防抖和节流?

防抖:通过setTimeout的方式,在一定的时间间隔内,将多次触发变成一次触发

节流:减少一段时间的触发频率

为什么要使用防抖和节流?

在实际开发过程中,前端的按钮交互等操作往往是和后端接口数据库紧密联系的

如果不对用户的交互操作加以限制,例如用户极其频繁地服务器发起请求,点击按钮,可能会影响到后端接口及服务器的正常运行或者造成页面卡顿等现象,使用防抖和节流就显得尤为重要了。

防抖

明确需求:在用户第一次点击之后的一段时间内,如果用户频繁点击,则不处理这个事件

很容易想到用定时器来处理,如果持续触发则清除这个定时器,这也运用到了闭包的思想

扩展:为了良好的用户体验,也可以设置在第一次点击时立即发送请求,而不是延时发送

实例

用一条输入框,以及一个按钮来模拟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<!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>防抖</title>
</head>
<body>
<input type="text">
<input type="submit" id="btn" value="点击">
<script>
let btn = document.querySelector("#btn"); //获取按钮
btn.addEventListener("click",debounce(submit,1000,true));

function submit(){
console.log(1);
}
//@param fn 传入的函数
//@param timer 延迟时间
//@param trigger 第一次是否立即触发
function debounce(fn,timer,trigger){
let t = null;//定时器
return function(){
if(t){
clearTimeout(t);
}
if(trigger){ //如果要求第一次立即执行
let firstClick = !t; //如果是第一次,那么firstClick为true
if(firstClick){
fn.apply(this,arguments);
}
t = setTimeout(()=>{
t = null; //过一段时间后再将t的值改回去
},timer)
}else{
t = setTimeout(()=>{ //注意这里的箭头函数
fn.apply(this,arguments);
},timer)
}
}
}
</script>
</body>
</html>

一些注意点:

  • 使用箭头函数,此时的this和arguments是上层的this和arguments

  • 点击一次之后,短时间内连续点击不会再执行,因为后续的t的值都不为null,而是一个个序列值,只有在等它变为null的时候才能继续执行

    t的值

节流

节流需要控制执行的频率而不管用户的操作,你点得再快,我也只隔一段事件后再操作,有时间戳版本和定时器版本

时间戳版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!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></title>
</head>

<body>
<input type="text">
<input type="button" value="点击" id="btn">

<script>
let btn = document.querySelector('#btn');
btn.addEventListener("click", throttle(submit, 2000));

function submit(){
console.log(1);
}
function throttle(fn,delay){
let begin = 0; //定义一个开始时间
return function(){
let cur = new Date().getTime(); //获取当前时间
if(cur-begin>delay){
fn.apply(this,arguments); //执行
begin = cur;
}
}
}

定时器版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!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></title>
</head>

<body>
<input type="text">
<input type="button" value="点击" id="btn">

<script>
let btn = document.querySelector('#btn');
btn.addEventListener("click", throttle(submit, 2000));

function submit(){
console.log(1);
}
function throttle(fn,delay){
let run = true;
return function(){
if(!run){
return; //在规定时间内其他定时器无法执行
}
run = false; //要开始执行了,屏蔽别的定时器
setTimeout(()=>{
fn.apply(this,arguments);
run = true; //当这个定时器执行完之后,再让别的定时器执行
},delay)
}
}

函数防抖和节流
https://blog-theta-ten.vercel.app/2021/10/04/函数防抖和节流/
作者
Chen
发布于
2021年10月4日
许可协议