JavaScript防抖和节流
问题还原
我们先来通过代码把常见的问题还原:
<html>
<head>
<meta charset="utf-8">
<title>问题演示</title>
</head>
<body>
<script type="text/javascript">
window.onload = function(){
// 没有处理防抖和节流的代码
let norInput = document.getElementById('normal');
let ajax = content=>{
console.log('ajax:' + content);
}
norInput.addEventListener('keyup',e=>{
ajax(e.target.value)
})
// console.log(debounce()())
}
</script>
<input type="text" name="normal" id="normal">
</body>
</html>
在上面的程序中,看上去是没有什么问题,但是用户每输入一个字符,都会向后端发起一次请求,而这只是一个用户,如果同时很多用户进行相同的操作,无异于是给服务端造成极大的压力。
而解决这种问题,有很多种合适的方法,但是下文要说到的,是关于JavaScript
当中的防抖
和节流
操作。
防抖
什么是防抖
当用户在触发一次事件n秒后在执行回调函数,如果重复触发则进行重新计时。
根据防抖
的逻辑,下面通过代码来进行模拟:
<html>
<head>
<meta charset="utf-8">
<title>问题演示</title>
</head>
<body>
<script type="text/javascript">
window.onload = function(){
let norInput = document.getElementById('normal');
// 创建一个函数模拟ajax请求
let ajax = content=>{
console.log('ajax:' + content);
}
// 创建防抖函数
let debounce = (fn,delay) => {
return function(args){
let that = this;
let param = args;
// 每次事件触发 清除当前的timmer 然后重写调用
clearTimeout(fn.id);
fn.id = setTimeout(function(){
fn.call(that,param)
},delay)
}
}
let deb_func = debounce(ajax,500)
norInput.addEventListener('keyup',e=>{
deb_func(e.target.value)
})
}
</script>
<input type="text" name="normal" id="normal">
</body>
</html>
上面的demo
运行后,你会发下,用户如果停止输入后的一段时间才会发起ajax
请求,而如果用户持续输入,则计时器会不断的刷新,再这个过程中并不会发生请求,直到用户停止输入,才会开始计时,时间一到,才会发送请求。
这样就能够有效的减少因为频繁发送请求给服务器带来过大的压力。
使用场景
- resize 事件或者scroll事件等,可以通过防抖减少触发次数
- 用户在输入框中频繁输入
节流
什么是节流
设置一个时间范围,在一定的时间范围内,仅允许执行一次执行一次事件的回调函数,也就是说只要在规定时间范围内,无论事件触发几次,都只能执行一次回调函数。
我们通过click
事件来还原下事故现场:
<html>
<head>
<meta charset="utf-8">
<title>节流</title>
</head>
<body>
<input type="button" id="btn" value="点击">
<script type="text/javascript">
let oBtn = document.getElementById('btn');
let ajax = ()=>{
console.log("ajax发送请求")
}
oBtn.addEventListener('click',()=>{
ajax();
})
</script>
</body>
</html>
当用户每一次点击后,都会发送一次请求,点击不断,请求不断。如同生命不息,战斗不止
。可想而知,一旦有人无聊的一直点击,那么请求次数将会变得很可观。
下面是我们根据节流
的原理来实现的示例代码:
<html>
<head>
<meta charset="utf-8">
<title>问题演示</title>
</head>
<body>
<script type="text/javascript">
window.onload = function(){
// 获取元素
let oBtn = document.getElementById('normal');
// 模拟ajax请求
let ajax = ()=>{
console.log("ajax发送请求....")
}
// 节流函数
let throttle = (func,wait) =>{
var timeout ;
var previous = 0;
return function(){
var _this = this;
args = arguments;
if(!timeout){
timeout = setTimeout(function(){
timeout = null;
func.apply(_this,args);
},wait)
}
}
}
let thro_func = throttle(ajax,3000);
// 绑定事件
oBtn.addEventListener('click',()=>{
thro_func();
})
}
</script>
<input type="button" name="normal" id="normal" value="点击">
</body>
</html>
通过上面的案例,我们可以做到,当用户点击一次后,计时器开始,这当中无论发生几次事件触发,都仅仅会执行一次回调。
当然,想要实现节流的方法不止使用定时器这一种方案,还可以选择使用时间戳,再或者其他方法也不是不行,本文的目的仅仅是为了阐述和说明
节流
和防抖
这两种减少服务器压力的方法而已。
使用场景
- 鼠标不断点击的情况
- 页面无限加载,每隔一段时间发起请求而不是用户停止滚动发起请求
- ...