知食记
搜索文档…
Debounce
防抖函数总结

定义

bounce即弹起,debounce的中文意思为“防抖“

场景

debounce个人理解的使用场景为,某种经常会触发的事件,等待稳定后最后一次性执行。比较典型的有:
  • 键盘输入事件捕捉。等待用户最后输入完成
  • scroll事件,等待用户最后滚动结束处理
  • resize事件,等待用户最后调整结束处理

实现

1
/// 返回一个函数,但是只要它一直持续地被调用,就不会被触发;除非它最后一次被调用停止了n毫秒
2
// 如果`immediate`参数被传递,那么会直接执行
3
function debounce(func, wait, immediate){
4
var timeout = null;
5
6
return excuteFunction(){
7
var context = this;
8
var args = arguments;
9
var later = function(){
10
timeout = null
11
if(!immediate) func.apply(context, args);
12
}
13
14
var callNow = immediate && !timeout;
15
if(callNow) func.apply(context, args);
16
17
// clearTimeout非常关键。如果在timeout完成后later调用前,excuteFunction又被调用,那么timeou会被清除,并接下来被重新赋值开始
18
clearTimeout(timeout)
19
20
timeout = setTimeout(later, wait);
21
}
22
}
Copied!

ES6 实现

1
function debounceES6(func, wait, immediate) {
2
let timeout
3
return (...args) => {
4
let callNow = immediate && !timeout
5
if (callNow) func.apply(this, args);
6
7
clearTimeout(timeout);
8
9
timeout = setTimeout(() => {
10
timeout = null
11
if (!immediate) func.apply(this, args)
12
}, wait);
13
}
14
}
Copied!

深度

GitHub有用户专门提到利用箭头函数对于this的处理,省略到context的写法
1
function debounce (fn, wait) {
2
let t
3
return function () {
4
clearTimeout(t)
5
t = setTimeout(() => fn.apply(this, arguments), wait)
6
}
7
}
Copied!
虽然绝大数情况下箭头函数会调用语义上正确的this,不过考虑如下场景,就会有错误
1
const obj = {
2
name: 'foo',
3
sayMyName() {
4
console.log('My name is', this.name)
5
}
6
}
7
8
obj.sayMyName() //-> My name is foo
9
obj.deb = debounce(obj.sayMyName, 1000)
10
obj.deb() // Should log -> My name is foo
Copied!
在省略context的写法下,只能输出,因为My name isobj的this没有绑定进去。
除非使用
1
obj.deb = debounce(obj.sayMyName.bind(obj), 1000)
2
obj.deb() // now -> My name is foo
Copied!