/// 返回一个函数,但是只要它一直持续地被调用,就不会被触发;除非它最后一次被调用停止了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);
}
}
ES6 实现
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 isobj的this没有绑定进去。
除非使用
obj.deb = debounce(obj.sayMyName.bind(obj), 1000)
obj.deb() // now -> My name is foo