本文已参与「新人创作礼」活动,一起开启掘金创作之路。
函数防抖(debounce)
基本概念:在事件被触发n秒在执行回调,如果在这n秒内又被触发,则重新开始计时。类型分为延时函数以及立即执行函数。
例子:日常生活中的电梯,在打开的时候会等待几秒钟然后在关闭,假设电梯等待的时间是5s ,假设场景:你在等电梯,电梯门开了你进入了,
等待五秒后电梯门自动关闭,但是在等待2s的时候又有人进来了,此时电梯感应到便重新开始计时。这就是防抖。电梯的防抖可以防止人被夹,
保证人员的安全,对于服务器来说可以保证节约服务器资源。减轻服务器压力。
延时函数示意图:
立即执行示意图:
普通防抖函数
function debounce(fun, delay) {
return function () {
clearTimeout(fun.id);
fun.id = setTimeout(() => {
fun.apply(this, arguments);
}, delay);
};
}
优化后的防抖函数
function uDebounce(fn, wait) {
let timer,
startTimeStamp = 0;
let args;
// run函数 wait时间到了进入。
let run = (timerInterval) => {
timer = setTimeout(() => {
// 设定当前时间
let now = new Date().getTime();
let interval = now - startTimeStamp;
// 最后一次点击时间和当前时间不足awit
if (interval < timerInterval) {
console.log("debounce reset", timerInterval - interval);
startTimeStamp = now;
// 再次生成一个定时器
run(wait - interval);
} else {
fn.apply(this, args);
clearTimeout(timer);
timer = null;
}
}, timerInterval);
};
return function () {
args = arguments;
// 每次触发事件便会设定startTimeStamp的时间
startTimeStamp = new Date().getTime();
// 初始进入或执行完回调函数可再次进入
if (!timer) {
run(wait);
}
};
}
立即执行防抖函数
function rightDebounce(fn, wait, immediate = true) {
let timer,
startTimeStamp = 0;
let args;
let run = (timerInterval) => {
timer = setTimeout(() => {
let now = new Date().getTime();
let interval = now - startTimeStamp;
if (interval < timerInterval) {
startTimeStamp = now;
run(wait - interval);
} else {
if (!immediate) {
fn.apply(this, args);
}
clearTimeout(timer);
timer = null;
}
}, timerInterval);
};
return function () {
args = arguments;
startTimeStamp = new Date().getTime();
if (!timer) {
if (immediate) {
fn.apply(this, args);
}
run(wait);
}
};
}
普通延时防抖:
1、 在防抖函数中使用了闭包。使得fun会一直存在。从而可以清除之前生成的定时器。 2、这是一个延时的防抖函数。并且会不断的创建销毁定时器。比较消耗资源,并不是最优的防抖函数。
优化后的防抖
// 从优化后的函数可以看出 1、初始会进入run()函数,在wait期间会不断刷新startTimeStamp的值,延时函数到时间执行时判断,最后一次的startTimeStamp和now是否小于wait,是的话则再次进行,由此执行的防抖不会频繁的创建销毁定时器。除去了销毁定时器的操作。
函数防抖总结:
1、防抖函数分为延时防抖和立即执行防抖,根据具体需求情况选取。
2、防抖函数可以在一定程度上防止资源浪费,减少不必要的接口请求,从而减轻服务器的压力。
3、防抖函数的实际应用场景:窗口大小改变事件onresize、联想搜索(当input框值改变时触发接口请求)、防止按钮重复点击按钮等。
4、如果有高频触发但是中间有停顿应该选取防抖。
函数节流(throttle)
基本概念: 规定在一个单位时间内,只能触发一次函数,如果这个时间内触发多次函数,那么只有一次函数生效
例子:大家玩的MOBA类游戏都有技能,技能释放完之后都有一定的缓冲时间,在释放完毕后不停的在按也不会触发,这里使用的就是节流,如果不做这个处理从技术的角度来看,服务器肯定会爆炸。
延时节流函数
function throttle(fn, wait) {
let timer, args;
let run = () => {
timer = setTimeout(() => {
fn.apply(this, args);
clearTimeout(timer);
timer = null;
}, wait);
};
return function () {
args = arguments;
if (!timer) {
run();
} else {
}
};
}
立即执行节流
function uthrottling(fn, wait, immediate) {
let timer,
timeStamp = 0;
let args;
let run = () => {
timer = setTimeout(() => {
if (!immediate) {
fn.apply(this, args);
}
clearTimeout(timer);
timer = null;
}, wait);
};
return function () {
args = arguments;
if (!timer) {
if (immediate) {
fn.apply(this, args);
}
run();
} else {
}
};
}Ï
节流函数总结:
1、在规定时间内只触发一次回调函数。
2、实际应用场景:下拉加载更多、onscroll
3、如果有高频触发但是没有停顿应该使用节流。
总体总结:无论是函数的节流或者防抖都是为了改善我们的代码性能,性能上去了,用户体验就会好。用户体验好了的话才能使得我们的产品持续发展下去,比如我们会在vue项目上做一些优化,分包、cdn加载资源文件、缓存、减少dom操作、压缩图片等等,但是如果你在联想搜索等场景下不做防抖节流处理,会不断的请求后台,性能差的手机肯定会卡,之前做了那么多优化,如果不处理这些又有啥意义呢?