0%

手写防抖与节流函数

防抖节流应用场景?

按照需求来确定是用防抖还是节流:

tips: 在连续频繁操作的时间区域内,要能执行函数的情况用节流。

  1. 监听浏览器resize事件;
  2. 文本编辑器实时保存;
  3. 输入框的模糊查询功能;

防抖函数

防抖的原理是什么?

防抖的原理就是:不管怎么触发事件,但是一定在事件触发 n 秒后才执行,如果一个事件触发的 n 秒内又触发了这个事件,那就以新事件的时间为准,n 秒后才执行,总之就是要等触发完事件 n 秒内不再触发事件才执行。

实现一个防抖函数?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const debounce = (fn, delay) => {
let timer = null
/**
* 返回值也是一个函数,函数内部的变量就是局部变量,可以避免造成全局污染;
* 注意:这里不能使用箭头函数,因为后面会用到this。
*/
return function () {
// 存储参数
let args = arguments
/**
* 除了第一次timers为null,后续函数的调用timer都有值;
* 这一步要做的是清除目前正在进行的定时器,即使时间到了也不能执行回调函数;
* 注意:clearTimeout(timer)执行之后,timer的值没变。
*/
if (timer) clearTimeout(timer)
// 将新的定时器赋值给timer
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}

节流函数

节流的原理是什么?

节流的原理是:一个函数执行一次后,只有大于设定的执行周期,才会执行第二次。也就是说:在规定的时间内,只让函数触发的第一次生效,后面的不生效。

实现一个节流函数?

1.使用定时器

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
const throttle = (fn, delay) => {
let timer = null
/**
* 返回值也是一个函数,函数内部的变量就是局部变量,可以避免造成全局污染;
* 注意:这里不能使用箭头函数,因为后面会用到this。
*/
return function () {
// 存储参数
let args = arguments
/**
* timer为null的两种情况:
* 1.第一次执行函数timer初始值为空;
* 2.每次定时器到时间了,执行回调时会将timer赋值为空。
*/
if (!timer) {
timer = setTimeout(() => {
/**
* 注意:这里直接将timer是赋值为null,而不是使用clearTimeout,
* 还是因为clearTimeout(timer)执行之后,timer的值没变
*/
timer = null
fn.apply(this, args)
}, delay)
}
}
}

2.使用时间戳

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function throttle_2(fn, delay) {
let previous = 0;
return function () {
// 存储参数
let args = arguments
const nowTime = Date.now()
/**
* 执行的两种情况:
* 1.第一次执行函数previous为0,nowTime-0>delay;
* 2.距离上一次执行时间超过了delay。
*/
if (nowTime - previous > delay) {
fn.apply(this, args)
previous = nowTime
}
}
}