跳到主要内容

Basic

2024年03月12日
柏拉文
越努力,越幸运

时间戳版

思路:用时间戳来判断是否已到执行时间,记录上次执行的时间戳,然后每次触发事件执行回调,回调中判断当前时间戳距离上次执行时间戳的间隔是否已经达到时间差(Xms) ,如果是则执行,并更新上次执行的时间戳,如此循环。

实现

function throttle(fn, wait) {
let previous = 0;
return function (...args) {
const context = this;
let now = +new Date();
if (now - previous > wait) {
previous = now;
fn.apply(context, args);
}
};
}

特点: 事件开始触发时立即执行回调

定时器版

思路: 使用定时器,比如当 scroll 事件刚触发时,打印一个 hello world,然后设置个 1000ms 的定时器,此后每次触发 scroll 事件触发回调,如果已经存在定时器,则回调不执行方法,直到定时器触发,handler 被清除,然后重新设置定时器。

实现:

function throttle(fn, wait) {
let timer = null;
return function (...args) {
const context = this;
if (!timer) {
timer = setTimeout(() => {
clearTimeout(timer);
timer = null;
fn.apply(context, args);
}, wait);
}
};
}

特点: 事件停止触发时,延迟执行回调

双剑合璧版

思想: 结合 throttle 和 debounce 代码,加强版节流函数 throttle 如下,新增逻辑在于当前触发时间和上次触发的时间差小于时间间隔时,设立一个新的定时器,相当于把 debounce 代码放在了小于时间间隔部分。

实现

function throttle(fn, wait) {
let timer = null;
let previous = 0;
return function (...args) {
const context = this;
const now = +new Date();
if (now - previous < wait) {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
previous = now;
fn.apply(context, args);
}, wait);
} else {
previous = now;
fn.apply(context, args);
}
};
}

特点: 事件触发开始时立即回调,事件触发结束后延迟执行回调(有头有尾)