一、是什么
二者本质上都是优化高频率执行代码的一种手段
1.节流(throttle):
定义:n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效。
2.防抖(debounce):
定义:n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时。
二、实现
1.节流:
在第一次触发事件的时候开启一个定时器,如果在定时器期间重复触发该事件,则不做任何操作。等定时器结束后执行事件。
使用定时器实现:
function throttled(fn, delay = 500) {
let timer = null
return function (...args) {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
}, delay);
}
}
}
也可以选择立即执行函数,然后n秒内不在执行
function throttled(fn, delay = 500) {
let timer = null
return function (...args) {
if (!timer) {
//立即执行
fn.apply(this, args)
timer = setTimeout(() => {
timer = null
}, delay);
}
}
}
或者使用这个:
function debounce(fn, delay = 500,immediate = true) {
let timer = null;
return function (...args) {
if (timer) {
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args);
timer = null;
},delay)
}
else {
fn.apply(this, args);
timer = setTimeout(() => {
timer = null;
}, delay);
}
};
}
2.防抖:
触发事件后开启定时器,期间再次触发则清除当前定时器,重新开启,直至最后一次的定时器结束,执行事件。
function debounce(fn, delay) {
let timeout;
return function () {
let context = this; // 保存this指向
let args = arguments; // 拿到event对象
clearTimeout(timeout)
timeout = setTimeout(function(){
fn.apply(context, args)
}, delay);
}
}
想要立即执行:
function debounce(fn, delay, immediate) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout); // timeout 不为null
if (immediate) {
let callNow = !timeout;//第一次timeout为undefin
if (callNow) {
fn.apply(context, args)
}
timeout = setTimeout(function () {
//用于最后一次触发函数
if(!callNow) {
fn.apply(context, args)
}
timeout = null;
}, delay)
}
else {
timeout = setTimeout(function () {
fn.apply(context, args)
}, delay);
}
}
}
三、应用场景
节流在间隔一段时间执行一次回调的场景有:
- 滚动加载,加载更多或滚到底部监听
- 搜索框,搜索联想功能
- 发送短信验证码
- 其他需要n秒后再操作的场景
防抖在连续的事件,只需触发一次回调的场景有:
- 搜索框搜索输入。只需用户最后一次输入完,再发送请求
- 手机号、邮箱验证输入检测
- 窗口大小
resize
。只需窗口调整完成后,计算窗口大小。防止重复渲染。