#43 函数防抖 debounce


  • 0
    administrators

    在前端开发当中,会遇到某个函数被高频率调用的情况。比如说用户疯狂地按住某个按钮,这些事件都会导致回调函数被高频地调用,但是高频调用这些函数可能会导致页面运行效率下降。

    于是就有了一种 debounce 的解决方案:如果你疯狂、高频地调用某个函数,而调用之间的时间间隔低于某个时间段,这个函数最后只会被执行一次;如果高于某个时间段,则会执行多次。

    请你完成 debounce,它接受两个参数,一个是被封装函数,一个是时间间隔(ms),然后返回一个函数。可以做到函数防抖的效果:

    window.addEventListener('resize', debounce(() => {
      console.log('Hello')
    }, 100))
    

  • 0

    刚过 520,周末还在出题啊


  • 0
    administrators

    @Sunjourney 这都被你发现了


  • 2

    @胡子大哈

    感觉这个这个 throttle 和我理解的 throttle 不一样啊。
    而调用之间的时间间隔低于某个时间段,这个函数最后只会被执行一次;如果高于某个时间段,则会执行多次。
    这句话,应该是 debounce 的描述,我理解的 debounce 是延迟执行,多次执行以最后一次为准,用于 search 框较多。resize 确实用 throttle,但应该是每到 throttle 执行最接近 throttle 的一次操作,也就是每过一个 duration,一定会执行一次,而不是 这个函数最后只会被执行一次

    有些 throttle 的实现是 debounce 的效果,但我认为不对,应该按 lodash 的定义来,要不胡子哥把标题改成 debounce ? 用例别用 resize,用搜索框?测试还可以继续用


  • 1
    administrators

    @Sunjourney 对的,是我搞错了。正在修改中


  • 0
    administrators

    @Sunjourney 已经改了描述,感谢建议。


  • 1
    管理员

    思路:debounce里定义一个局部变量timer,再写一个闭包去控制这个timer。
    timer写在闭包外是只执行一次的,而闭包函数在监听过程中是执行多次的。

    const debounce = (fn, duration) => {
      let timer = null;
      return () => {
        clearTimeout(timer)
        timer = setTimeout(() => {
          fn()
        }, duration)
      }
    }

  • 0

    @陈小俊#43 函数防抖 debounce 中说:

    timer = null


  • 0

    @陈小俊 你好,setTimeout的第一个参数为什么外面要多一层匿名函数呢?我不加这个匿名函数也能通过测试用例


  • 0

    @ScriptOJ
    这个该怎么和点击事件联合使用啊,大神


  • 0

    @陈小俊#43 函数防抖 debounce 中说:

    const debounce = (fn, duration) => {
    let timer = null;
    return () => {
    clearTimeout(timer)
    timer = setTimeout(() => {
    fn()
    }, duration)
    }
    }

    duration有作用吗?


  • 0

    var debounce = (n) => {
    	var old
    	return e => {
    		var gap =+new Date - old
    		if(gap /1000 <= n){
    			console.log('正忙...')
    			return
    		}
    		old = +new Date()
    		console.log('test')
    	}
    }
    
    

  • 0

    let debounce = (fn, duration) => {

    var curTime=0
    
    return function akb() {
        if ( (new Date().getTime() - curTime )> duration) {
            
      
            curTime = new Date().getTime()
            fn();
        }
    }
    

    }
    这样写在浏览器测试是可以的,可是不通过


  • 0

    @okaykop 一旦到了duration, 就一定会执行请求,但这时,可能仍在高频请求


  • 0

    @okaykop 这个应该就是实现了前面贴子提到的throttle,而不是debounce


  • 0

    之前把函数防抖和函数节流弄反了,现在搞懂了。


  • 0

    按正常思路就可以了 ,没有那么麻烦,注意题目要求返回一个函数,不就是闭包嘛

    const debounce = (fn, duration) => {
      let timer = null
      return () => {
        clearTimeout(timer)
        timer = setTimeout(fn,duration)
      }
    }
    

  • 0

    0_1549463403754_#43 函数防抖 debounce.png


  • 0

    函数节流debounce

    多用于搜索框,当其被疯狂、高频地点击,这个函数最后只会被执行一次。

    实现思路: 每次点击都先清除之前的timer,然后重新设定定时器,以确保fn只执行一次

    const debounce = (fn, duration) => {
          let timer = null
          let fns = () => {
            clearTimeout(timer)
            timer = setTimeout(fn,duration)
          }
         return fns
    }
    

    函数节流throttle

    多用于具有倒计时功能的按钮,当点击发送按钮后,开始进行倒计时,这期间无法发送,当倒计时结束后,可再次发送

    实现思路: 在发送后开始倒计时,倒计时结束后清除timer,这期间所有请求全部 return false

    const throttle= (fn, duration) => {
        let timer = null;
        let fns = () => {
            if (timer) {
                return false;
            } else {
                timer = setTimeout(() => {
                    timer = null;
                }, duration);
                return fn();
            }
        };
        return fns;
    };
    
    

登录后回复
 

与 ScriptOJ 的连接断开,我们正在尝试重连,请耐心等待