什么是防抖和节流?
从本质上来说,防抖和节流是为了节省浏览器消耗,将短时间内的频繁的操作只执行一次。比如mouseMove,click,input事件,这些事件被绑定之后,可能被频繁的触发,像频繁点击按钮,鼠标滑轮一直滚动,输入框的输入事件,这些都会被不断地触发,现在就有了防抖和节流的概念,去减少操作,降低浏览器消耗。
防抖和节流的本质区别在哪?
防抖是某段时间内,如果一直触发某个事件,只会被执行一次。
节流是某段时间内如果一直触发事件,则会在规定的时间内每几秒执行一次,会不停地执行。
下面看防抖和节流的代码:
//防抖 立即执行操作,即达到状态立即执行操作
function debounce(func,wait){
let time
return function(){
let self=this //为了保证下面箭头函数中的this指向不受影响
if(time) clearTimeout(time)
let flag=!time //这里time被清除之后,还剩下一个数字字段,所以!time得到的是false
time=setTimeout(()=>{
time=null;
},wait)
if(flag) func.apply(self,arguments)
}
}
//后执行操作,即完成这次操作之后,等到规定时间才会执行
function debounce(func,wait){
let self=this
let time
if(time) cleatTImeout(time)
time=setTimeout(()=>{
time=null
func.apply(self,arguments)
},wait)
}
从上述代码可以看到,是将内容以闭包的形式返回了,这里为了保证time的值被保存,下一次再调用函数时,相当于调用了上次闭包返回的值,相当于上次的结束时的状态。
一行一行的来看代码,先设置一个time值,为了下面能够调用,形成闭包。接着返回一个匿名函数,将这次执行完的状态返回。下一行if(time)代表如果time为true,则执行清除定时器。那么什么时候time才会为true?可以看到第一次执行时,time执行到这一行,还是空对象,之后被赋值一个定时器,所以在第一秒内的第二次之后的执行time都是true,一直执行if循环,清除定时器
那么在一直触发这个函数的时候,time定时器会一直被清除,而没有机会给time赋值为null,只有在执行了一次操作之后等待一秒,这时候time被赋值为null,再次执行函数,flag就是true,才能确保一直点击只会触发一次。
//节流 方法一:
function throttle(func,wait){
let self=this;
let time=0;
return function(){
const now=Date.now();
if(now-time>wait){
func.apply(this.argiments)
time=now
}
}
}
方法二:
function throttle(func,wait){
let self=this
let time
return function(){
if(!time){
time=setTimeout(()=>{
time=null
func.apply(this.arguments)
},wait)
}
}
}
节流的思想是在一个时间段内,每隔多久执行一次。从上述代码可以看出来节流是通过设置1s后才改变这个状态,才可以继续执行下一次操作。
从代码可以看出来都是当下一次操作距离上一次操作的间隔大于设置的时间的时候,才会执行操作。
下面是完整的代码,可以看到效果:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="content"
style="height:150px;line-height:150px;text-align:center; color: #fff;background-color:#ccc;font-size:80px;"></div>
<script>
let num = 1;
let content = document.getElementById('content');
function count() {
content.innerHTML = num++;
};
content.onmousemove = debounce(count,1000);
function throttle(func, wait) {
let previous = 0;
return function () {
let now = Date.now();
let args = arguments;
if (now - previous > wait) {
console.log(args)
func.apply(this, args);
previous = now;
}
}
}
function throttleTimer(func,wait){
let time
return function(){
let context=this
let args=arguments;
if(!time){
time=setTimeout(()=>{
time=null
func.apply(context,args)
},wait)
}
}
}
function debounce(func, wait) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) {
clearTimeout(timeout);
// console.log(timeout);
} //0
let callNow = !timeout; //1
// console.log(callNow)
timeout = setTimeout(() => {
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
}
</script>
</body>
</html>
以上是在js中的基本使用,下面看一下在vue中看一下怎么使用防抖和节流
就从最基础的输入框事件说起,我们知道有些输入框是输入的时候要发送请求的,如果一直发送请求,就会大大影响性能,所以我们要根据需要进行防抖或者节流。
先想一下防抖和节流的根本思想:
防抖:·如果一直执行,就会一直往后计算开始的时间,只有等停下操作的时候才会真正的执行操作。用代码来想就是:在规定的时间单位内,如果一直执行操作就会一直清除定时器,直至最后没有操作了,在延时之后触发事件。
节流:每隔一段时间就执行一次,原来return出去的函数是为了拿到上一步执行的time,这里可以把变量存在data中,会随着更新。在第一秒内,time第一次被赋值之后!time就一直就是false,就不会触发内部的方法,一秒之后被赋值为空之后,才能执行下一次操作。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0,minimal-ui:ios">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" @input="search" v-model="text" >
</div>
<script>
var vm = new Vue({
el:'#app',
data:{
// search:'',
time:'',
text:'',
count:1,
msg:'测试'
},
methods:{
input(value){
console.log(value)
this.count++
console.log('count is:' + this.count)
},
search() {
//节流
// if(!this.time){
// // console.log("aaa")
// this.time=setTimeout(()=>{
// this.input("ceshi")
// this.time=null
// },1000)
// }
//防抖
if (this.time) {
clearTimeout(this.time)
}
this.time = setTimeout(() => {
// binding.value()
this.input("ceshi")
// time=null
}, 300)
// 实际要进行的操作 axios.get('')之类的
}
},
}) ;
</script>
</body>
</html>