前言
首先明白一点,防抖和截流都是用于 高频 的 异步 触发场景,目的都是为了让事件只触发一次。例如按钮不停的提交表单(异步操作),滚动条的上拉加载数据(异步操作),输入框的搜索联想(异步操作)等。区分防抖和截流在于高频点击 第一次 触发事件后,是否立马执行和 再次 触发事件后的反应。 记住第一次事件就生效,还是延迟生效,就能理顺防抖和截流的区别了。
防抖(debounce)
事件被触发延迟n秒后执行,如果在这n秒内又被触发,则重新计时。 个人理解:最后一次事件经过n秒后执行。
从防抖的定义来考虑代码怎么写:
- 延迟n秒后执行(有定时器)
- n秒内触发,重新计时(第二次触发事件的时候,定时器会被清空)
function debounce(fn, delay) {
let timer; // 定时器对象
return function(...args) {
// 2. 如果定时器对象存在,则清除重新计时
timer && clearTimeout(timer);
// 1. 主逻辑,延迟n秒后执行
timer = setTimeout(()=> {
fn.apply(this, args); // Todo:执行你的函数
timer = null;
},delay);
}
}
截流(throttle)
事件被触发后立即执行,如果在这n秒内又被触发,则不会生效。个人理解:第一次事件执行后,n秒后才能再执行。
从截流的定义来考虑代码怎么写:
- 触发事件后,立即执行
- n秒内触发,不生效(现在的时间跟之前时间比,是否经过n秒,经过n秒触发才生效)
function throttle(fn, delay) {
// 需要3个时间:当前时间 now、延迟时间 delay、最后时间 last
let last = 0;
return function(...args) {
const now = +new Date(); // 获得当前时间
// 1. 触发事件后,立即执行函数,第一次 now - last 永远大于 延迟时间
// 2. 前后两次事件时间对比,是否过了设定的延迟时间。
if(now - last > delay) {
last = now;
fn.apply(this, args); // Todo:执行你的函数
}
}
}
应用场景
防抖
- 搜索,输入联想
- window触发 resize时间,窗口大小改变
截流
- 表单提交,按钮点击
- 滚动上拉加载