一、使用时间戳
function throttle1(fn, wait) {
let previous = 0;
return function () {
let now = new Date().getTime();
if (now - previous > wait) {
fn.apply(this, arguments);
previous = now;
}
}
}
- 注:当鼠标移入的时候,事件立刻执行,每过 1s 会执行一次,如果在 4.2s 停止触发,以后不会再执行事件。
二、使用定时器
function throttle(fn, wait) {
let timer;
return function () {
if (!timer) {
timer = setTimeout(() => {
timer = null;
fn.apply(this, arguments);
}, wait)
}
}
}
- 注:当鼠标移入的时候,事件不会立刻执行,晃了 3s 后终于执行了一次,此后每 3s 执行一次,当数字显示为 3 的时候,立刻移出鼠标,相当于大约 9.2s 的时候停止触发,但是依然会在第 12s 的时候执行一次事件。
- 区别:
(1) 第一种事件会立刻执行,第二种事件会在 n 秒后第一次执行
(2) 第一种事件停止触发后没有办法再执行事件,第二种事件停止触发后依然会再执行一次事件
三、两种结合使用
function throttle(fn, wait) {
let timer;
let previous = 0;
let throttled = function () {
let now = +new Date();
// remaining 不触发下一次函数的剩余时间
let remaining = wait - (now - previous);
if (remaining < 0) {
if (timer) {
clearTimeout(timer);
timer = null;
}
previous = now;
fn.apply(this, arguments)
} else if (!timer) {
timer = setTimeout(() => {
previous = new Date().getTime();
timer = null;
fn.apply(this, arguments);
}, remaining);
}
}
return throttled;
}
- 注意:这个综合了两者的优势,鼠标移入能立刻执行,停止触发的时候还能再执行一次!
四、可配置(立即执行但结束后不执行,不立即执行但结束后要执行一次)
- leading:false 表示禁用第一次执行
- trailing: false 表示禁用停止触发的回调
function throttle(fn, wait, options = {}) {
let timer;
let previous = 0;
let throttled = function () {
let now = +new Date();
// remaining 不触发下一次函数的剩余时间
if (!previous && options.leading === false) previous = now;
let remaining = wait - (now - previous);
if (remaining < 0) {
if (timer) {
clearTimeout(timer);
timer = null;
}
previous = now;
fn.apply(this, arguments)
} else if (!timer && options.trailing !== false) {
timer = setTimeout(() => {
previous = options.leading === false ? 0 : new Date().getTime();
timer = null;
fn.apply(this, arguments);
}, remaining);
}
}
return throttled;
}
注意:那就是 leading:false 和 trailing: false 不能同时设置。
节流:在规定时间内,保证执行一次该函数。
防抖:当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。