zoukankan      html  css  js  c++  java
  • 节流throttle和防抖debounce

    underscore.js提供了很多很有用的函数,今天想说说其中的两个。这两个函数都用于限制函数的执行。

    debounce

    在解释这个函数前,我们先从一个例子看下这个函数的使用场景。假设我们网站有个搜索框,用户输入文本我们会自动联想匹配出一些结果供用户选择。我们可能首先想到的做法就是监听keypress事件,然后异步去查询结果。这个方法本身是没错的,但是如果用户快速的输入了一连串的字符,假设是10个字符,那么就会在瞬间触发了10次的请求,这无疑不是我们想要的。我们想要的是用户停止输入的时候才去触发查询的请求,这时候函数防抖可以帮到我们。

    函数防抖就是让某个函数在上一次执行后,满足等待某个时间内不再触发此函数后再执行,而在这个等待时间内再次触发此函数,等待时间会重新计算。

    我们先看下underscore.js里相关函数的定义:

    _.debounce(function, wait, [immediate])

     
    // Returns a function, that, as long as it continues to be invoked, will not
    // be triggered. The function will be called after it stops being called for
    // N milliseconds. If `immediate` is passed, trigger the function on the
    // leading edge, instead of the trailing.
    _.debounce = function(func, wait, immediate) {
      var timeout, args, context, timestamp, result;
    
      var later = function() {
        var last = _.now() - timestamp;
    
        if (last < wait && last >= 0) {
          timeout = setTimeout(later, wait - last);
        } else {
          timeout = null;
          if (!immediate) {
            result = func.apply(context, args);
            if (!timeout) context = args = null;
          }
        }
      };
    
      return function() {
        context = this;
        args = arguments;
        timestamp = _.now();
        var callNow = immediate && !timeout;
        if (!timeout) timeout = setTimeout(later, wait);
        if (callNow) {
          result = func.apply(context, args);
          context = args = null;
        }
    
        return result;
      };
    };
    简单版,自己实现

    function
    debounce(fn,time){ var isRun = false; function later(){ fn(); isRun = false; } return function(){ if(!isRun){ isRun = true setTimeout(later,time); } }}

    参数function是需要进行函数防抖的函数;参数wait则是需要等待的时间,单位为毫秒;immediate参数如果为true,则debounce函数会在调用时立刻执行一次function,而不需要等到wait这个时间后,例如防止点击提交按钮时的多次点击就可以使用这个参数。

    所以,上面那个场景,我们可以这么解决:

    function query() { 
      //进行异步调用查询 
    }
    
    var lazyQuery = _.debounce(query, 300);
    $('#search').keypress(lazyQuery);

    throttle

    我们网站经常会有这样的需求,就是滚动浏览器滚动条的时候,更新页面上的某些布局内容或者去调用后台的某接口查询内容。同样的,如果不对函数调用的频率加以限制的话,那么可能我们滚动一次滚动条就会产生N次的调用了。但是这次的情况跟上面的有所不同,我们不是要在每完成等待某个时间后去执行某函数,而是要每间隔某个时间去执行某函数,避免函数的过多执行,这个方式就叫函数节流

    同样的,我们看下underscore.js里相关函数的定义:

    _.throttle(function, wait, [options])

    // Returns a function, that, when invoked, will only be triggered at most once
    // during a given window of time. Normally, the throttled function will run
    // as much as it can, without ever going more than once per `wait` duration;
    // but if you'd like to disable the execution on the leading edge, pass
    // `{leading: false}`. To disable execution on the trailing edge, ditto.
    _.throttle = function(func, wait, options) {
      var context, args, result;
      var timeout = null;
      var previous = 0;
      if (!options) options = {};
      var later = function() {
        previous = options.leading === false ? 0 : _.now();
        timeout = null;
        result = func.apply(context, args);
        if (!timeout) context = args = null;
      };
      return function() {
        var now = _.now();
        if (!previous && options.leading === false) previous = now;
        var remaining = wait - (now - previous);
        context = this;
        args = arguments;
        if (remaining <= 0 || remaining > wait) {
          if (timeout) {
            clearTimeout(timeout);
            timeout = null;
          }
          previous = now;
          result = func.apply(context, args);
          if (!timeout) context = args = null;
        } else if (!timeout && options.trailing !== false) {
          timeout = setTimeout(later, remaining);
        }
        return result;
      };
    };

     简单版,自己实现。

    function throttle(fn,time){
        var id ;
        return function(){
                if(id) clearTimeout(id);
            id=setTimeout(fn,time);
        }
    }

    参数function是需要进行函数节流的函数;参数wait则是函数执行的时间间隔,单位是毫秒。option有两个选项,throttle第一次调用时默认会立刻执行一次function,如果传入{leading: false},则第一次调用时不执行function。{trailing: false}参数则表示禁止最后那一次延迟的调用。具体可以看源码进行理解。

    所以,在滚动滚动条的场景,我们可以这么做:

    function handleScroll() { 
      //进行滚动时的相关处理 
    }
    
    var throttled = _.throttle(handleScroll, 100);
    $(window).scroll(throttled);

    参考

    http://underscorejs.org/#debounce
    http://underscorejs.org/#throttle

    可参考:https://css-tricks.com/the-difference-between-throttling-and-debouncing/

    【原文】https://segmentfault.com/a/1190000002764479

  • 相关阅读:
    外校培训前三节课知识集合纲要(我才不会告诉你我前两节只是单纯的忘了)
    floyd算法----牛栏
    bfs开始--马的遍历
    (DP 线性DP 递推) leetcode 64. Minimum Path Sum
    (DP 线性DP 递推) leetcode 63. Unique Paths II
    (DP 线性DP 递推) leetcode 62. Unique Paths
    (DP 背包) leetcode 198. House Robber
    (贪心 复习) leetcode 1007. Minimum Domino Rotations For Equal Row
    (贪心) leetcode 452. Minimum Number of Arrows to Burst Balloons
    (字符串 栈) leetcode 921. Minimum Add to Make Parentheses Valid
  • 原文地址:https://www.cnblogs.com/sivkun/p/7440330.html
Copyright © 2011-2022 走看看