最近偶尔也会出去面面试,两次被问到函数去抖和函数截流,特别是公司项目没有引入loadsh库,刚好也需要用到去抖,博主在一家交易所(虚拟币交易)上班,有一次,进行币币交易的时候,下单时由于网络延迟比较高,下单页面没有及时跳转,以为没有成功,就多点击了一下,结果下了两单...我靠这是bug呀(第一版是外包做的)吓得我赶紧写了个去抖函数。
Vue.prototype.is_locked = Symbol('is_loacked') // 定义一个不存在的变量 当做函数是否被锁的属性
Vue.prototype.debounce = function(func = _ => undefiened, interval = 0, ...args) {
const { is_locked } = Vue.prototype
if(func[is_locked]){
return
}
func[is_locked] = true
func.apply(this, args)
setTimeout(_ => func[is_locked] = false, interval)
}
这个函数的思路是实现一个代理函数debounce
将你的函数func
作为参数传递给debounce
,以及函数触发后应该被锁定的时间interval
,并且告诉debounce
要执行的函数的参数args
。
代理函数在执行 func
之前会检查这个函数是否处于锁定期(is_locked
),若果处于锁定期直接结束函数,否则就会先给函数上锁,然后立即调用,之后会在约定解锁的时间将锁解除。
而函数截流,可以通过封装去抖函数实现,也可以单独实现,暂时就不讨论了😄。
以上这个版本还有一些缺陷,那就是当某个函数被大量复用的时候,会造成其他调用者也无法调用的情况,我们需要改进一下这个函数,让debounce
能聪明的识别不同的调用者
让其对不同的调用者独立记时。
改版
Vue.prototype.$is_locked = Symbol('$is_locked')
Vue.prototype.$caller_set = Symbol('$caller_set')
// 函数去抖
Vue.prototype.debounce = function (func = _ => undefined, interval = 0, ...args) {
const {$is_locked, $caller_set} = Vue.prototype
// 如果函数因为未达到解锁时间而处于锁定状态,直接结束函数
if (func[$is_locked] && func[$caller_set] && func[$caller_set].has(this)) return
// 否则锁住这个函数
func[$is_locked] = true
if(func[$caller_set] === undefined){
func[$caller_set] = new Set()
}
// 把调用者加入set
func[$caller_set].add(this)
// 立即调用
func.apply(this, args)
// 等达到去抖保护时间后解锁函数,并且去掉调用者。
setTimeout(_ => {
func[$is_locked] = false
func[$caller_set].delete(this)
}, interval)
}