防抖debounce
概念
事件被触发经过单位时间(delay)后再执行回调如果在单位时间内又被触发则重新计时。
防抖函数
const debounce = (cb, delay = 1000) => {
let timer = null;
return function (...args) {
const context = this;
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
cb.apply(context, args);
timer = null;
}, delay);
}
}
若延迟delay设置为1000(默认值)则cb(回调函数)只会在停止触发1s后执行如果一直不断地触发则回调函数始终不执行。
使用
下面是一个简单的使用示例后续介绍的防抖和节流函数的使用方式也是相似的。
const callback = () => {
console.log(Math.random());
}
const handle = debounce(callback, 1000);
window.addEventListener('scroll', handle);
防抖函数(第一次触发会立即执行)
const debounceImmediate = (cb, delay = 1000, immediate = true) => {
let timer = null;
return function (...args) {
const context = this;
const execNow = immediate && !timer;
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
cb.apply(context, args);
timer = null;
}, delay);
execNow && cb.apply(this, args);
}
}
当设置immediate=true(默认值)、delay=1000(默认值)时第一次触发会立即执行回调函数。后续执行和普通的防抖函数一样只有在停止触发1s后回调函数才会执行如果还是一直不断地触发则回调函数始终不执行。
节流throttle
概念
规定在单位时间(delay)内只能触发一次函数。如果单位时间内多次触发函数只会执行一次回调。
节流函数(使用时间戳)
const throttleUseTimeStamp = (cb, delay = 1000) => {
let startTime = Date.now();
return function(...args) {
const context = this;
const now = Date.now();
if (now - startTime >= delay) {
cb.apply(context, args);
startTime = Date.now();
}
}
}
若delay=1000则在1s内只会执行一次回调函数。
节流函数的实现(使用定时器)
const throttleUseTimer = (cb, delay) => {
let timer = null;
return function(...args) {
const context = this;
if (!timer) {
timer = setTimeout(() => {
cb.apply(context, args);
timer = null;
}, delay);
}
}
}
若delay=1000则在1s内只会执行一次回调函数。
节流函数的实现(第一次触发立即执行最后一次触发也会执行)
const throttleExecMore = function(cb, delay) {
let timer = null;
let startTime = Date.now();
return function(...args) {
const curTime = Date.now();
const remaining = delay - (curTime - startTime);
const context = this;
timer && clearTimeout(timer);
if (remaining <= 0) {
// 第一次触发执行
cb.apply(context, args);
startTime = Date.now();
} else {
// 最后一次触发也会执行
timer = setTimeout(() => {
cb.apply(context, args);
timer = null;
}, remaining);
}
}
}
第一次触发会立即执行回调函数最后一次触发也会执行一次回调函数。
亲自体验
将前面介绍的5种防抖和节流函数分别应用在5个输入框的onChange事件的监听上delay值统一设置为1000快速输入1111得到结果如下
完全符合我们前面的分析。
如果不加防抖、节流控制得到结果将是
1
11
111
1111
触发了4次回调函数。
体验网址二维码
应用场景举例
防抖
- 搜索联想在不断输入值时节约请求资源。
- 窗口resize事件
节流
- 鼠标不断点击单位时间内只触发一次
- 滚动到底部加载更多