防抖的应用场景
- scroll事件滚动触发
- 搜索框输入查询
- 表单验证
- 按钮提交事件
- 浏览器窗口缩放,resize事件
防抖的原理
原理:n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
举例:
事件响应函数在一段时间后才执行,如果在这段事件内再次调用,则重新计算执行时间;当预定的时间内没有再次调用该函数,则执行dosomething函数。
<style>
#container{
width: 100%;
height:200px;
line-height: 200px;
text-align: center;
color:#fff;
background-color: #444;
font-size: 30px;
}
</style>
<body>
<div id="container"></div>
//引入underscore库,其中的debounce可以实现防抖
<script src="http://cdn.bootcss.com/underscore.js/1.9.1/underscore.js"></script>
<script>
let count = 0
//演示时间是如何频繁发生的
let container = document.querySelector('#container')
function doSomeThing(){
//可能会做回调或者ajax请求
container.innerHTML = count++;
}
//_.debounce(高阶函数)对doSomething函数进行包装,第一个参数为被包装函数的函数名,第二个参数为时间,表示多少毫秒后执行
//第三个参数表示是否立即执行,如果设置true表示立即执行,默认值是不会立即执行container.onmousemove = _.debounce(doSomeThing,2000,true);
container.onmousemove = _.debounce(doSomeThing,2000);
</script>
</body>
防抖的分类
防抖分为立即防抖和非立即防抖:
-
立即防抖:多次触发事件,第一次会立即执行函数,之后在设定wait时间内触发的事件无效,不会执行。
-
非立即防抖:多次触发事件,只会在最后一次触发事件后等待设定的wait时间结束时执行一次。
手写防抖函数(debounce)
初步实现防抖函数:
index.html文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
#container{
width: 100%;
height:200px;
line-height: 200px;
text-align: center;
color:#fff;
background-color: #444;
font-size: 30px;
}
</style>
<body>
<div id="container"></div>
<!-- //引入debounce.js文件 -->
<script src="./debounce.js"></script>
</body>
</html>
js文件:
//防抖的函数
//这里用到了闭包
function debounce(func,wait,immediate){
let timeout;
return function(){
//改变执行函数内部this的指向,让this指向container
let context = this;
//参数
let args = arguments;
clearTimeout(timeout)//只清除定时器,不清除timeout的值
if(immediate){
//立即执行:多次触发事件,第一次会立即执行函数,之后在设定wait时间内触发的事件无效,不会执行。
//callNow来记录是否立即执行,callNow为true立即执行
let callNow = !timeout;
//wait时间内(timeout有值,callNow为false)不会立即执行
//wait时间到了(timeout值置为null,callNow为true)立即执行
timeout = setTimeout(()=>{
timeout = null;
},wait);
if(callNow){
func.apply(context,args)
}
}else{
//非立即执行:多次触发事件,只会在最后一次触发事件后等待设定的wait时间结束时执行一次。
timeout = setTimeout(()=>{
func.apply(context,args)
},wait)
}
}
}
let count = 0;
//演示时间是如何频繁发生的
let container = document.querySelector("#container");
function doSomeThing() {
//可能会做回调或者ajax请求
container.innerHTML = count++;
}
container.onmousemove = debounce(doSomeThing, 300,true);
防抖函数中返回值和取消操作的实现:
index.html文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
#container{
width: 100%;
height:200px;
line-height: 200px;
text-align: center;
color:#fff;
background-color: #444;
font-size: 30px;
}
</style>
<body>
<div id="container"></div>
<button id="btn">取消防抖</button>
<!-- //引入debounce.js文件 -->
<script src="./debounce.js"></script>
</body>
</html>
js文件:
//防抖的函数
function debounce(func,wait,immediate){
var timeout,result;
var debounced = function(){
//改变执行函数内部this的指向,让this指向container
var context = this;
//参数
var args = arguments;
if(timeout) clearTimeout(timeout);
if(immediate){
var callNow = !timeout;
timeout = setTimeout(()=>{
timeout = null;
},wait);
if(callNow){
result = func.apply(context,args)
}
}else{
timeout = setTimeout(()=>{
func.apply(context,args)
},wait)
}
return result;
}
//取消防抖
debounced.cancel = function(){
clearTimeout(timeout)
//防止内存泄露
timeout = null;
}
return debounced;
}
let count = 0;
//演示时间是如何频繁发生的
let container = document.querySelector("#container");
let btn = document.querySelector('#btn')
function doSomeThing() {
//可能会做回调或者ajax请求
container.innerHTML = count++;
return '想要的结果'
}
let doSome = debounce(doSomeThing,1000);
//点击按钮,取消防抖
btn.onclick = function(){
doSome.cancel()
}
//给container绑定鼠标移动事件
container.onmousemove = doSome;