美文网首页李南江JavaScript程序设计
如何理解debounce和throttle?

如何理解debounce和throttle?

作者: 趁你还年轻233 | 来源:发表于2019-01-09 15:53 被阅读35次

    前端工程师们都听过看起来很高级的词,节流和防抖,其实节流就是debounce,防抖就是throttle,其实这个也属于前端性能优化的一部分。

    在做远程搜索时,如果每输入1个字就调用1次接口,就会频繁查询数据库,假设我们的查询是"一二三四五",不考虑用户输入错误的情况,至少会请求5次。

    • 有没有一种方法,可以隔个几百毫秒再去查询呢?
    • 有没有更加高级的做法,用户输入完成后,停顿了几百毫秒再去查询呢?

    有没有一种方法,可以隔个几百毫秒再去查询呢?

    有,可以为函数设置一个setTimeout函数,相当于定时调用接口,这种方法是低效的,也是非常愚蠢的,需要控制开关定时器,一旦搜索功能多了,就更蠢了。

    有没有更加高级的做法,用户输入完成后,停顿了几百毫秒再去查询呢?

    有,debounce就是做这个事情的,lodash从0.1.0就支持了这个方法。

    css-tricks的lodash debounce demo

    <input type="text" class="autocomplete">
    
    // 被debounce的函数,http请求,事件处理函数等等
    function make_ajax_request(){
        // 这是一个调用后端api的方法
    }
    // 监听事件并且调用lodash的debounce方法
    $('.autocomplete').on('keydown',
         _.debounce(make_ajax_request, 1300));
    });
    

    demo地址:https://codepen.io/dcorb/embed/mVGVOL?height=257&theme-id=1&slug-hash=mVGVOL&default-tab=result&user=dcorb

    vue项目中的lodash debounce demo

    <template>
      <input @input="debounceHandleInput"/>
    </template>
    
    <script>
    import _ from 'lodash';
    
    export default {
      name: 'debounce',
      data() {
        return {
          starTime: 0,
          endTime: 0,
          delay: 1000,
        };
      },
      computed: {
        debounceHandleInput() {
          return _.debounce(this.handleInput, this.delay);
        },
      },
      methods: {
        handleInput(e) {
          console.log(`debounce wait时间为${this.delay}ms`);
          console.log('触发了input事件', e.target.value);
          this.startTime = new Date().getTime();
          this.remoteMethod();
        },
        remoteMethod() {
          setTimeout(() => {
            const result = `后端请求已完成!`;
            this.endTime = new Date().getTime();
            const costTime = this.endTime - this.startTime;
            console.log(result);
            console.log(`耗时${costTime}毫秒`);
          }, 2000);
        },
      },
    };
    </script>
    

    打印结果:
    debounce wait时间为1000ms
    触发了input事件 13131
    后端请求已完成!
    耗时2000毫秒

    在1000ms时间范围内触发,仅仅调用一次remoteMethod,也就是仅仅调用一次后端接口,达到我们的预期效果。

    debounce适用场景

    • Debouncing a input event handler (this example explain this use case)
    • Debouncing a resize event handler
    • Debouncing a save function in an autosave feature

    在做滚动加载时,如果用户滚动的幅度过大,会导致加载的内容过多,相当于水的流量没有控制,一瞬间大量的水量迸发而出,从而所看到的延后好几个与预期的下一个不符的情况

    • 当水流超过阀值时,最多释放出阀值量的水;水流小于阀值时,一切正常。有没有一种办法去控制水流的大小?

    有,throttle就是做这个事情的,lodash从0.1.0也支持了这个方法。

    具体demo就不写了,因为throttle常用于连续事件的事件处理函数

    可以参考 https://css-tricks.com/the-difference-between-throttling-and-debouncing/ 文章最后的demo,其中的throttle在scroll上的运用,就是throttle的正确打开方式。

    image

    throttle适用场景

    • Throttling a scroll event in infinite scroll(demo case)
    • Throttling a mousemove/touchmove event handler in canvas

    debounce和throttle的对比

    地址:http://demo.nimius.net/debounce_throttle/
    图片:

    image

    通过在canvas上连续触发mousemove事件我们发现:

    • debounce只有当连续事件停止后的一小段时间后再触发一次,连续事件结束后可能只触发一次
    • throttle会在连续事件的过程中,每隔一段时间至少触发一次,连续事件结束后触发不止一次

    努力成为一个不掉队的前端工程师!

    相关文章

      网友评论

        本文标题:如何理解debounce和throttle?

        本文链接:https://www.haomeiwen.com/subject/vudgrqtx.html