防抖
防抖即“防止抖动”,当我们频繁触发一个事件时,每次事件都会执行,会造成不必要的性能损失。
防抖就是要延迟执行,在频繁触发事件时,让某个函数只能执行最后一次。
我们一直触发事件,但是不执行,只有在停止操作一段时间后才执行,就好像电脑的休眠,只有在一段时间内没有使用电脑,电脑才会休眠,如果在这一段时间内使用了电脑,那么电脑就重新开始倒计时。
下面是一个防抖函数的简单版本:
let timer: any;
function debounce(func: Function, delay: number) {
return function () {
clearTimeout(timer);
timer = setTimeout(() => {
func();
}, delay);
};
}
通过延时函数,在触发事件后,先将之前的setTimeout清除,然后重新定义timer重新计时,如果在delay的时间内,没有重复触发,那么函数顺利执行,如果被重复触发,那就再重新计时。
但这还没完全结束,在js中,这时在func内部打印this,会发现这样执行的话this指向的是window,所以需要使用apply改变this指向。
另外要考虑到func接收的参数,不同的函数会有不同的参数传入,对于参数可以使用arguments处理。
let timer;
function debounce(fun,delay){
return function(){
clearTimeout(timer);
let args = arguments;
timer=setTimeout(()=>{
fun.apply(this,args)
},delay)
}
}
节流
节流的概念是:在单位时间内,频繁触发事件,只执行一次。
比如我最近在做的项目:地图组件+时间轴组件,当在时间轴上切换不同的时间点时,会根据时间点,请求该时间点对应的强对流信息png图(降水、雷暴等),然后将图片渲染在地图上,显示该时间点的强对流色斑图。在渲染一张png时,要创建新的色斑图图层,在离开该时间点时,要将该图层销毁,但是这个过程需要时间,于是就出现bug了:在频繁切换时间点的时候,地图报错:在销毁时找不到你说的图层!!
因为切换太快了,这个图层甚至还没来得及创建,就要被销毁,自然而然产生报错,这时候就需要使用节流,防止一段时间内的多次触发。
let t1: any = 0;
function throttle(func: Function, time: number) {
return function () {
let t2: any = new Date();
if (t2 - t1 > time) {
func();
t1 = t2;
}
};
}
记录两个时间,t1代表初始时间,t2代表当前时间,如果两个时间差值大于time,就执行func并且将初始时间变更为func最新执行的时间。
对于防抖和节流一个最主观的判断方法就是:在10s内疯狂点击一个按钮,如果使用了防抖则会只执行一次,使用了节流则会每隔一段时间执行一次,这个时间可以自己来掌控。
封装防抖函数:
/**
* 为目标函数添加防抖
* @param func 目标函数
* @param time 防抖时间间隔
* @param immediately 是否立刻执行
* @returns 防抖的目标函数
*/
export function antiShake<T extends (...args: any) => void>(func: T, time = 0, immediately = false): T {
let handler: any = 0;
let lock = 0;
// 立即执行
if (immediately) {
return function (...args: any) {
const now = Date.now();
if (handler) {
clearTimeout(handler);
}
if (lock < now) {
func(...args);
lock = now + time;
} else {
handler = setTimeout(() => {
handler = 0;
func(...args);
}, time);
}
} as T;
}
// 不立刻执行
else {
return function (...args: any) {
if (handler) {
clearTimeout(handler);
}
handler = setTimeout(() => {
handler = 0;
func(...args);
}, time);
} as T;
}
}
网友评论