Javascript防抖与节流示例详解
Javascript防抖与节流示例详解
防抖和节流本质上是优化高频率执行代码的一种手段
如:浏览器的 resize
、scroll
、keypress
、mousemove
等事件在触发时,会不断地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能
为了优化体验,需要对这类事件进行调用次数的限制,对此我们就可以采用 防抖(debounce) 和 节流(throttle) 的方式来减少调用频率
定义
- 防抖: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
- 节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
防抖(debounce)
触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。(可以将防抖类比成电梯:第一个人进电梯之后,电梯会在5秒之后自动关闭电梯门,如果在这5秒内又有人进来了,那么电梯会重新等待5秒后再关门。)
应用场景:input搜索框,用户连续输入,等输入停下来或结束时再去触发搜索接口
实现:
1、简单版本的实现
// fn 是事件处理程序,
// delay 是事件执行的延迟时间,单位:毫秒
function debounce(fn, delay){
let timer = null;
return function(...args) {
const _this = this;
// 每次触发事件 都把定时器清掉重新计时
clearTimeout(timer);
timer = setTimeout(function() {
// 执行事件处理程序
fn.call(_this, args);
}, delay);
}
}
2、立即执行版本实现,可加入第三个参数用于判断:
// fn 是事件处理程序
// delay 是事件执行的延迟时间,单位:毫秒
// immediate 是否立即执行
function debounce(func, delay, immediate) {
let timeout;
return function (...args) {
const _this = this;
if (timeout) {
clearTimeout(timeout);
}
if (immediate) {
let callNow = !timeout; // 第一次会立即执行,以后只有事件执行后才会再次触发
timeout = setTimeout(() => {
timeout = null;
}, delay);
if (callNow) {
func.apply(_this, args);
}
} else {
timeout = setTimeout(() => {
func.apply(_this, args);
}, delay);
}
}
}
节流(throttle)
当持续触发事件时,保证一定时间段内只调用一次事件处理函数。所以节流会稀释函数的执行频率
应用场景:按钮重复提交、滚动条事件、resize事件等高频监听事件
实现
1、使用时间戳实现
事件会立即执行,停止触发后没有办法再次执行
// fn 是事件处理程序
// delay 是事件执行的延迟时间,单位:毫秒
function throttle(fn, delay = 100) {
// 定义初始时间(开始触发事件的时间)
let oldTime = Date.now();
return function(...args) {
const _this = this;
// 获取当前时间戳
const newTime = Date.now();
// 判断当前时间与初始时间是否超过间隔
if (newTime - oldTime >= delay) {
// 执行事件处理程序
fn.call(_this, args);
// 更新初始时间
oldTime = Date.now();
}
};
}
2、使用定时器实现
delay
毫秒后第一次执行,第二次事件停止触发后依然会再一次执行
// fn 是事件处理程序,
// delay 是事件执行的延迟时间,单位:毫秒
function throttle(fn, delay = 100) {
let timer = null;
return function (...args) {
const _this = this;
if (!timer) {
timer = setTimeout(() => {
// 执行事件处理程序
fn.call(_this, args);
// 事件执行完后把定时器清除掉,下次触发事件的时候再设置
timer = null;
}, delay);
}
};
}
3、时间戳和定时器结合
function throttle(fn, delay = 100) {
let timer = null;
let startTime = Date.now();
return function (... args) {
const _this = this;
// 当前时间
let curTime = Date.now();
// 从上一次到现在,剩余时间
let remaining = delay - (curTime - startTime);
clearTimeout(timer);
if (remaining <= 0) {
fn.apply(_this, args);
starttime = Date.now();
} else {
timer = setTimeout(fn, remaining);
}
}
}
作者:Lyove
What's Your Reaction?