用途
在开发中经常会遇到一些频繁的事件触发,如 onscroll
,oninput
之类的等事件。其实为了实现我们最终的功能,频繁触发的事件也许只有最后一次触发才是我们想要的,那么防抖函数就是干这个用途的。我们给它一个时间,告诉该函数,当前设定的时间内,只执行一次该函数,这样就减少了非必要事件的执行。
案例
现在我们设定一个案例来实践一下,比如说,我们在一次滚动事件,只想要滚动的最终值。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
#parent{
height: 100px;
border: 1px solid #ccc;
overflow-y: scroll;
}
#child{
height: 1000px;
}
</style>
</head>
<body>
<div id="parent">
<div id="child"></div>
</div>
<script>
let $parent = document.querySelector("#parent");
// 先要初始化一次,保证调用的过程中都是调用同一个闭包返回的函数
let dobounceFn = dobounce(getScrollVal, 1000);
$parent.onscroll = function(e){
dobounceFn($parent.scrollTop);
}
// 很明显,利用了防抖后,我们的功能函数每秒只会取一次值
function getScrollVal(){
console.log($parent.scrollTop)
}
// 防抖
// 1、防止函数多次重复执行
function dobounce(fn, wait){
let timer = null;
return function(){
if(timer){
clearTimeout(timer);
}
let context = this;
let args = arguments;
timer = setTimeout(function(){
fn.call(context, args )
}, wait)
}
}
</script>
</body>
</html>
代码分析
防抖的代码其实很简短,但是却用到了定时器、闭包,call,对于创造出这个函数的大佬真是佩服。
setTimeout
。这个就不用说了,一次性定时器call
。重新绑定this
的指向 ,然后将内置返回函数的参数arguments
传给fn
闭包
。外层函数返回内层函数,内层函数使用了外层函数作用域中的变量,很经典。这里通过对外层函数中的timer
进行重复利用,实现清除wait
时间内的所有非最后一次事件触发;
/**
* 防抖函数
* @param { Function } fn
* @param { Number } wait
*/
function dobounce(fn, wait){
let timer = null;
return function(){
if(timer){
clearTimeout(timer);
}
let context = this;
let args = arguments;
timer = setTimeout(function(){
fn.call(context, args )
}, wait)
}
}