函数防抖:
通俗概念:如果单位时间内,多次触发只让他触发一次
作用:防止短时间内多次触发方法,造成浏览器抖动或卡顿
原理:当触发某次事件之后一段时间内,在没有触发事件,那么该次事件回调会被执行。
封装一个用来输出函数
var i = 0;
function handleClickCount(){
console.log(this,ev); //输出this指向,以及事件类型 this指向button
console.log(i++); //输出次数
}
/*
btn.onclick = handleClickCount() 就相当于
btn.onclick = function handleClickCount(){...}
*/
//调用该输出函数
btn.onclick = handleClickCount() //不防抖的情况
//debounce 去除抖动 antiShake 防抖
btn.onclick = debounce(handleClickCount(),2000) //防抖调用
普通版本的防抖:
弊端就是第一次点击事件时也会被防抖,只要点击了不管点击多少下都是在设置的防抖时间到了后执行
function debounce(func,wait){
let timer = null;
console.log(this) //指向window
return function(){ //return里的this指向的是btn
const context = this;
//因为return里的this指向的是btn,所以要将return中的this赋值给context,这样在setTimeout中就可
//以强转了
const arg = arguments;
clearTimeout(timer);
//延时器开始之前先清除一次延时器,然后再重新启动一个新的延时器,这样就等于你在延时时间内点击多少
//次都会清除延时,重新开始计时。
timer = setTimeout(function(){
func.apply(context,arg) //强制转换this指向
},wait);
}
}
输出结果:
上述代码中因为this指代已经被强制转换成btn了,而btn身上还添加一个鼠标的点击事件,所以结果如图。【注】要注意this的指向问题,不要搞混
另外两种普通版本写法
1、
出现这种结果的原因是因为this指代的问题,在setTImeout以及setInterval中this指代都是window同时在window的身上没有事件发生,所以arguments为undefined。
下面的情况也是一样因为this指代问题,回调函数没有设置任何值,而这个回调函数还是在setTimeout中,setTimeout本身就是window下的方法,所以最终this的返回值都是window,arguments都为undefined
2、
立即执行版本:
点击后立即执行,然后在防抖时间内怎么点击都不会有任何反应,只有到了设置的防抖时间后点击才会触发
function debounce(func,wait,immediate){ //immediate 是否立即执行 true/false
let tiemr = null;
return function(){
const context = this;
const arg = arguments;
const now = !timer;
clearTiemout(timer)
if(immediate){
if(now){
func.apply(context,arg)
}
timer = setTimeout(() =>{timer = null},wait)
}else{
timer = setTimeout(() => {func.apply(context,arg)},wait)
}
}
}
首先进行判断immediate是否为true,为true说明是立即执行,紧接着就要判断now是否为真,为真的话说明timer是空的(非空即真,非零即真),间接说明要判断timer是否为空,为空的话直接调用func函数输出,然后设置一个延时器将timer重新清空,不然的话就不会走immediate这条线,会直接走else路线。
输出结果:
跟上述普通版的防抖基本一样,都是this指代问题
【注】主要就是setTimeout中this的问题
应用场景
应用场景有很多,只要有需要频繁触发事件的基本都可以用到函数防抖以及函数节流(如果不懂什么事函数节流可以看看这个,要是看不懂的话那就是在下功力不够深厚,没有解释透彻),例如:输入框持续输入,将输入内容远程校验、多次触发点击事件、onScroll等等。
总结:
简单来说就是在规定时间里无论事件触发多少次总是只会执行最后一次事件的回调方法,从而减少浏览器的性能消耗