防抖和节流

防抖和节流

通常应用在输入查询,滚动加载,抢票,窗口改变等应用场景。

防抖

一句话概括:高频函数连续调用时,空闲时间必须大于给定时间。

原理就是利用异步函数来延时执行。

首先实现结束边界版 (结束边界就是在空闲时间结束时执行) es6 版

1
2
3
4
5
6
7
8
9
10
// func 要防抖的函数
// wait 空闲时间
// flag boolean 开始边界 结束边界
function debounce(func, wait, flag){
let timer = null;
return function(){
if(timer) clearTimeout(timer);
timer = setTimeout(()=>func.call(this),wait);
}
}

实现结束边界版 (结束边界就是在空闲时间结束时执行) es5 版

主要是异步函数牵涉到的执行上下文问题

1
2
3
4
5
6
7
8
9
10
11
12
13
// func 要防抖的函数
// wait 空闲时间
// flag boolean 开始边界 结束边界
function debounce(func, wait, flag){
var timer = null;
return function(){
var self = this;
if(timer) clearTimeout(timer);
timer = setTimeout(function(){
func.call(self)
},wait);
}
}

实现开始边界版 (开始边界就是在空闲时间开始时执行) es6

通过 flag 来开关这个功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// func 要防抖的函数
// wait 空闲时间
// flag boolean 开始边界 结束边界
function debounce(func, wait, flag){
let timer = null;
return function(){
if(timer) clearTimeout(timer);
if(flag){
// 开始边界
// 在 timer === null 时立即执行函数
// 同时开启延时函数 timer = null
if(!timer){
func.call(this)
}
timer = setTimeout(() => {
timer = null
}, wait);
}else{
// 结束边界
timer = setTimeout(()=>func.call(this),wait);
}
}
}

节流

将连续执行优化为每隔一段时间执行

也就是说异步函数已经在执行,那么就不会开另外一个异步函数

我们来代码翻译这句话

es5
1
2
3
4
5
6
7
8
9
10
11
function throttle (func, wait){
var timer = null;
return function(){
var self = this;
if(timer) return;
timer = setTimeout(function(){
func.call(self)
timer = null
}, wait);
}
}

节流立即执行

es6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function throttle(func, wait, flag){
let timer = null
return function(){
if(timer) return;
if(flag){
func.call(this)
timer = setTimeout(function(){
timer = null
}, wait);
}else{
timer = setTimeout(()=>{
func.call(this)
timer = null
}, wait)
}
}
}

每隔地段时间执行一次

1
2
3
4
5
6
7
8
9
10
function throttle(func, wait){
let previous = 0
return function(){
let now = +new Date()
if(now - previous >= wait){
func.call(this)
previous = now
}
}
}

注意

通常防抖和节流函数是用在异步函数中的,所以 定义函数的地方 不能使用 箭头函数

例如例子中的 return function()

错误用法,无法获取被点击的对象

1
2
3
button.addEventListener('click', () => {
this.classList.toggle('on');
});

lodash

lodash 防抖函数实现

1
_.debounce(func, [wait=0], [options={}])