description |
---|
防抖函数总结 |
bounce即弹起,debounce的中文意思为“防抖“
debounce个人理解的使用场景为,某种经常会触发的事件,等待稳定后最后一次性执行。比较典型的有:
- 键盘输入事件捕捉。等待用户最后输入完成
- scroll事件,等待用户最后滚动结束处理
- resize事件,等待用户最后调整结束处理
/// 返回一个函数,但是只要它一直持续地被调用,就不会被触发;除非它最后一次被调用停止了n毫秒
// 如果`immediate`参数被传递,那么会直接执行
function debounce(func, wait, immediate){
var timeout = null;
return excuteFunction(){
var context = this;
var args = arguments;
var later = function(){
timeout = null
if(!immediate) func.apply(context, args);
}
var callNow = immediate && !timeout;
if(callNow) func.apply(context, args);
// clearTimeout非常关键。如果在timeout完成后later调用前,excuteFunction又被调用,那么timeou会被清除,并接下来被重新赋值开始
clearTimeout(timeout)
timeout = setTimeout(later, wait);
}
}
function debounceES6(func, wait, immediate) {
let timeout
return (...args) => {
let callNow = immediate && !timeout
if (callNow) func.apply(this, args);
clearTimeout(timeout);
timeout = setTimeout(() => {
timeout = null
if (!immediate) func.apply(this, args)
}, wait);
}
}
GitHub有用户专门提到利用箭头函数对于this的处理,省略到context的写法
function debounce (fn, wait) {
let t
return function () {
clearTimeout(t)
t = setTimeout(() => fn.apply(this, arguments), wait)
}
}
虽然绝大数情况下箭头函数会调用语义上正确的this,不过考虑如下场景,就会有错误
const obj = {
name: 'foo',
sayMyName() {
console.log('My name is', this.name)
}
}
obj.sayMyName() //-> My name is foo
obj.deb = debounce(obj.sayMyName, 1000)
obj.deb() // Should log -> My name is foo
在省略context的写法下,只能输出,因为My name is
obj的this没有绑定进去。
除非使用
obj.deb = debounce(obj.sayMyName.bind(obj), 1000)
obj.deb() // now -> My name is foo