去抖函数的实现

451 阅读2分钟

最近偶尔也会出去面面试,两次被问到函数去抖和函数截流,特别是公司项目没有引入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)
}