0%

自己实现简单的函数防抖(debounce)和函数节流(throttle)

前言

前端的交互中,有些操作需要持续触发,而且频率非常高。比如:resize, scroll, mousemove, input 等事件。而为了性能和效率,我们不需要让事件触发太多次。这就诞生了函数的防抖和节流。

防抖(debounce)

防抖简单说就是在设定的时间内,虽然操作上持续触发,通过定时器约束,我们也只执行函数触发的最后一次。

防抖函数可以分为延迟执行版和立即执行版

延迟执行版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
fn: 需要防抖的函数
wait: 延迟毫秒数
return: 函数
*/
// 延迟执行
function debounce(fn, wait) {
var timer; // 全局的定时器 id
return function () {
var that = this; // 将函数被调用时的 this 保存
var args = arguments; // 保存函数的参数
if (timer) {
clearTimeout(timer); // 清除 wait 时间内频繁调用函数产生的定时器
}
timer = setTimeout(() => {
fn.apply(that, args); // 将传递进来的 fn 使用 apply 调用,将 this 指向改为保存的 that,同时进行传参
}, wait);
};
}

立即执行版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 立即执行
function debounce(fn, wait) {
var timer;
return function () {
var that = this;
var args = arguments;
if (timer) {
clearTimeout(timer);
}
if (!timer) fn.apply(that, args); // 首次进入, timer 为空,执行 fn 函数
timer = setTimeout(() => {
timer = null; // wait 毫秒后设置 timer 为空
}, wait);
};
}

防抖应用场景

  • reseize 事件
  • 按钮 click 控制

节流(throttle)

节流就是按照给定的时间有规律的执行函数,可以通过时间戳和定时器实现。

节流函数可以分为定时器版和时间戳版

定时器版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 定时器版
function throttle(fn, wait) {
let timer;
return function () {
const that = this;
const args = arguments;
if (!timer) {
timer = setTimeout(() => {
fn.apply(that, args);
timer = null;
}, wait);
}
};
}

时间戳版

1
2
3
4
5
6
7
8
9
10
11
12
13
// 时间戳版
function throttle(fn, wait) {
let previous = 0;
return function () {
const that = this;
const args = arguments;
let now = Date.now();
if (now - previous > wait) {
fn.apply(that, args);
previous = now;
}
};
}

节流应用场景

  • 元素拖动
  • 搜索联想
  • 移动端上滑加载时判断距离底部的位置