先简明扼要概括一下:
-- 区别:
函数防抖是单位时间内只执行一次;
函数节流是间隔时间执行,不管事件触发有多么的频繁,都会保证在规定时间内执行一次真正的事件处理函数。
-- 原理:
防抖是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,都会清除当前的 timer 然后重新设置超时调用,即重新计时。这样一来,只有最后一次操作能被触发。
节流是通过判断是否到达一定时间来触发函数,若没到规定时间则使用计时器延后,而下一次事件则会重新设定计时器。
防抖:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Document</title>
<style>
body{
height: 3000px;
}
</style>
</head>
<body>
<input type="text" id="inp">
</body>
</html>
<script>
let oInp=document.getElementById('inp');
function nice(fn,time){
let timer =null;
return arg=>{
clearTimeout(timer);
timer=setTimeout(()=>{
fn.call(this,arg)
},time)
}
}
let getFn = nice(ajax,1000);
function ajax(data){
console.log(data,"我拿到数据了");
}
// 键盘事件
oInp.addEventListener('keyup',(e)=>{
getFn(e.target.value)
});
// 滚动条滚动事件
document.body.onscroll=function(e){
getFn(e.timeStamp)
}
</script>
节流:(包含了防抖)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Document</title>
<style>
body{
height: 3000px;
}
</style>
</head>
<body>
<input type="text" id="inp">
</body>
</html>
<script>
let oInp=document.getElementById('inp');
function nice(fn,time){
let last,
timer =null;
return arg=>{
// 每次操作事件(滚动/输入)触发时,都会得到一个最新的时间毫秒数
let now = Date.now();
//如果上一次存在(有操作)并且上一次的时间+定时器间隔时间 > 现在的时间,说明现在这个操作是在我定时器触发的时间内的,
if(last && last + time > now){
// 那么下一次再进来,就要清除之前的定时器,重新计时。这是做了防抖
// 那就把之前的定时器清除重新计时,1S后执行函数。
clearTimeout(timer);
timer=setTimeout(()=>{
last=now; // 每次重新更新上一次的时间,这样在定时器间隔时间内,last+time 就会永远> now,造成if条件恒成立,也就会1秒执行一次事件函数
fn.call(this,arg)
},time)
}else{ //初始状态或操作间隔>定时器时间(1s),就会立即执行(ajax函数)
last = now; // 每次重新更新上一次的时间
fn.call(this,arg)
}
}
}
let getFn = nice(ajax,1000);
function ajax(data){
console.log(data,"我拿到数据了");
}
// 键盘事件
oInp.addEventListener('keydown',(e)=>{
getFn(e.target.value)
});
// 滚动条滚动事件
document.body.onscroll=function(e){
getFn(e.timeStamp)
}
</script>
以上代码可以运行一下去感受一下。
vue中使用:
<template>
<div class="box">
<el-input @keydown.native="keyDownFn" type="text" v-model="value"/>
</div>
</template>
<script>
export default {
data () {
return {
value:'',
timer :null,
now:'',
last:'',
}
},
methods:{
keyDownFn(e){
let getFn = this.nice(this.ajaxFn,1000);
getFn(e.target.value);
},
nice(fn,time){
return arg=>{
this.now = Date.now();
if(this.last && this.last + time > this.now){
clearTimeout(this.timer);
this.timer=setTimeout(()=>{
this.last=this.now;
fn.call(this,arg)
},time)
}else{
this.last = this.now;
fn.call(this,arg)
}
}
},
ajaxFn(data){
console.log(data,'我拿到数据了');
}
},
}
</script>
<style>
.box{
padding: 100px;
}
</style>
参考:
https://zhuanlan.zhihu.com/p/51608574
1 <!DOCTYPE html>
2 <html lang="en">
3
4 <head>
5 <meta charset="UTF-8">
6 <meta http-equiv="X-UA-Compatible" content="IE=edge">
7 <meta name="viewport" content="width=device-width, initial-scale=1.0">
8 <title>防抖节流</title>
9 <style>
10
11 </style>
12 </head>
13
14 <body>
15 <div>
16 防抖:<input type="text" id="inp1">
17 </div>
18 <div>
19 节流:<input type="text" id="inp2">
20 </div>
21 <div>
22 节流(第一次直接拿到数据):<input type="text" id="inp3">
23 </div>
24 </body>
25
26 </html>
27 <script>
28 var oInp1 = document.getElementById("inp1");
29 var oInp2 = document.getElementById("inp2");
30 var oInp3 = document.getElementById("inp3");
31
32 // 防抖
33 function debonce(fn, delay) {
34 var timer = null;
35 return (() => {
36 clearTimeout(timer)
37 timer = setTimeout(() => {
38 fn()
39 }, delay)
40 })
41 }
42
43 // 模拟接口ajax获取到的数据
44 function getData1() {
45 console.log(Math.random());
46 }
47 var fn1 = debonce(getData1, 500);
48 oInp1.addEventListener('keydown', fn1);
49
50 // ------------------------------------------------------------------------------------------------------
51 function getData2(data) {
52 console.log(data);
53 }
54
55 // 节流
56 function throttle1(fn, delay) {
57 var timer = null;
58 var oldTime = Date.now();
59 return (arg) => {
60 var nowTime = Date.now();
61 if (nowTime - oldTime > delay) {
62 clearTimeout(timer)
63 oldTime = nowTime;
64 timer = setTimeout(() => {
65 fn.call(this, arg);
66 }, delay)
67 }
68 }
69 }
70
71 var fn2 = throttle1(getData2, 1000);
72 oInp2.addEventListener('keyup', (e) => {
73 fn2(e.target.value)
74 });
75 // ------------------------------------------------------------------------------------------------------
76
77 function getData3(data) {
78 console.log(data);
79 }
80
81 // 节流2 -> 上次发生事件的时间+定时器间隔时间<现在的时间,证明过期了,就直接取到数据
82 function throttle2(fn, delay) {
83 var timer = null;
84 var oldTime = null;
85 return (arg) => {
86 var nowTime = Date.now();
87 if (oldTime && oldTime + delay > nowTime) {
88 clearTimeout(timer)
89 timer = setTimeout(() => {
90 oldTime = nowTime;
91 fn.call(this, arg);
92 }, delay)
93 } else {
94 oldTime = nowTime;
95 fn.call(this, arg);
96 }
97 }
98 }
99
100 var fn3 = throttle2(getData3, 1000);
101 oInp3.addEventListener('keyup', (e) => {
102 fn3(e.target.value)
103 });
104 </script>