概念
1、防抖(debounce):连续x时间内没有再次触发才执行回调函数。
根据需求场景的不同,分为计时前触发和计时后触发,这里我把它们叫做前置防抖和后置防抖(可能有别的叫法)
2、节流(throttle):x时间内的全部触发只执行一次。同样可以有前置和后置。
应用场景和区别
这里举例几个实际应用需求,加深对二者的理解和区分
防抖应用场景
修改用户信息时,提交按钮点击过快会造成多次API请求;
节流应用场景
浏览器播放条每1秒计算一次进度;
节流和防抖都可用的应用场景
拖动浏览器窗口大小,造成resize计算过多卡死;
文档编辑中实现实时保存;
input搜索框随用户输入实时更新搜索建议;
综上场景大概可以总结出
用户不停地操作,你想等用户停下来再交互的,用防抖;
用户不停地操作,你想每隔一段时间交互一次的,用节流;
实现
有时间戳和定时器两种实现方式,时间戳我还没有研究过,二者暂时也没发现优劣(欢迎补充指正),所以我就用定时器实现了。
关键思路:
防抖:触发时重新计时;
节流:计时结束标志;
// 防抖前置
function debounce(fn,time) {
let timer;
return function () {
clearTimeout(timer); //触发时重新计时
let callNow = !timer
timer = setTimeout(() => {
timer = null;
}, time);
if(callNow){
fn.apply(this, arguments);
}
};
}
function callBackDebounce() {
console.log('防抖:前置执行');
}
var submit = document.getElementById('submit');
submit.addEventListener('click', debounce(callBackDebounce,5000));
// 防抖后置
function debounce(fn,time) {
let timeout = null;
return function () {
clearTimeout(timeout); //触发时重新计时
timeout = setTimeout(() => {
fn.apply(this, arguments);
}, time);
};
}
function callBackDebounce() {
console.log('防抖:后置执行');
}
var submit = document.getElementById('submit');
submit.addEventListener('click', debounce(callBackDebounce,5000));
//节流前置
function throttle(fn,time) {
let timer;
let timeout = true;
return function () {
if(timeout){
fn.apply(this, arguments);
}
if(timeout){
timeout = false;
timer = setTimeout(() => {
clearTimeout(timer);//注意这个clear的位置跟防抖的区别
timeout = true; //计时结束标志
}, time);
}
};
}
function callBackThrottle(e) {
console.log(e.target.innerWidth, e.target.innerHeight);
}
window.addEventListener('resize', throttle(callBackThrottle,2000));
// 节流后置
function throttle(fn,time) {
let timer;
return function () {
if(!timer){
timer = setTimeout(() => {
fn.apply(this, arguments);
clearTimeout(timer)//注意这个clear的位置跟防抖的区别
timer = null; //计时结束标志
}, time);
}
};
}
function callBackThrottle(e) {
console.log(e.target.innerWidth, e.target.innerHeight);
}
window.addEventListener('resize', throttle(callBackThrottle,2000));