• 函数节流和函数防抖


    这段时间去面试了两家当前比较拽的互联网公司,回来一总结,广度略有,深度堪忧。这么看来可能觉得还是好事,最近没事在掘金上看看,不知不觉的关注的标签已经有40来个了。

    eslint,requirejs,three,Web Components,函数式编程,Visual Studio Code,JSON,TypeScript,vuex,WebAssembly,HTTPS,WebGL,DOM,Canvas,敏捷开发,MVVM,React Native,响应式设计,HTTP,全栈,稀土,电子书,chrome,微信,代码规范,CSS,正则表达式,Node.js, 前端框架, HTML,设计模式,面试,程序员,算法,架构,Webpack......

    bla bla bla......

    前端就是苦,前端就是累。代码大家都能写,写出什么样的代码,那就是功力。

    闲话说的太多了,前端时间自己用vue写了个相当简单的web音乐播放器,写完毕以后一直有几个问题困扰我。

    1.vue如何高可用的组件开发。

    2.自己写的搜索(autoComplete),返回数据不准确,可能返回以前关键字查询的结果。

    3. vuex 如何在错误的时候不阻止程序的继续执行。

    这里我说的是第二个问题,

    我原来的考虑,搜索的时候传递关键字过去, 返回的时候,除了被搜索到的数据,还包括关键字本身。

    如果当前的输入框的值和返回的数据的关键字匹配,那么展现,反之丢弃。

    这里也有问题,如果关键字前后两次相同,那就会数据填充两次。比如关键字为  a->b->a,第一个a落后于b返回。但至少保证了展现的数据是自己期望的数据。

    后来看了一下

    百度的搜索,也是每次都发送请求,但是一些前面发送的请求会被取消掉,返回html和脚本

    bing的搜索,也是每次都发送请求,没有取消,返回数据,html和脚本。

    搜狗,每次发送请求,没有取消,返回的是数据+脚本。

    但是都一个特点,就是返回的都足够快,这就有点尴尬了。

    回头再看看自己搜索的问题,才发现问题的是自己的逻辑处理问题

    1.当字符为空的时候没有发请求但是没有清空数据

    2.oninput,focus处理有问题

    晕死,一天在掘金看到函数节流和函数防抖,本事想应用到这个及时搜索上面来,可是啊哈,走歪了。

    回归,我们来说说函数节流和函数防抖。

    函数节流 & 函数防抖

    Throttling enforces a maximum number of times a function can be called over time. As in "execute this function at most once every 100 milliseconds".

    Debouncing enforces that a function not be called again until a certain amount of time has passed without it being called. As in "execute this function only if 100 milliseconds have passed without it being called".

    函数节流:是确保函数特定的时间内至多执行一次

    函数防抖:是函数在特定的时间内不被再调用后执行

    函数节流underscore的实现(解释,借用的是JS魔法堂:函数节流(throttle)与函数去抖(debounce))

    复制代码
    .throttle = function(func, wait, options) {
        /* options的默认值
         *  表示首次调用返回值方法时,会马上调用func;否则仅会记录当前时刻,当第二次调用的时间间隔超过wait时,才调用func。
         *  options.leading = true;
         * 表示当调用方法时,未到达wait指定的时间间隔,则启动计时器延迟调用func函数,若后续在既未达到wait指定的时间间隔和func函数又未被调用的情况下调用返回值方法,则被调用请求将被丢弃。
         *  options.trailing = true; 
         * 注意:当options.trailing = false时,效果与上面的简单实现效果相同
         */
        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;
          // 当到达wait指定的时间间隔,则调用func函数
          // 精彩之处:按理来说remaining <= 0已经足够证明已经到达wait的时间间隔,但这里还考虑到假如客户端修改了系统时间则马上执行func函数。
          if (remaining <= 0 || remaining > wait) {
            // 由于setTimeout存在最小时间精度问题,因此会存在到达wait的时间间隔,但之前设置的setTimeout操作还没被执行,因此为保险起见,这里先清理setTimeout操作
            if (timeout) {
              clearTimeout(timeout);
              timeout = null;
            }
            previous = now;
            result = func.apply(context, args);
            if (!timeout) context = args = null;
          } else if (!timeout && options.trailing !== false) {
            // options.trailing=true时,延时执行func函数
            timeout = setTimeout(later, remaining);
          }
          return result;
        };
      };
    复制代码

     略有复杂,我们当然有简单版本 ,基本的思想就是利用闭包生成一个新的执行函数,闭包里面记录上一次的调用时间,再次调用时时间差和允许的调用周期比较。

    复制代码
    function throttle(method,delay,duration){
      var timer=null, begin=new Date();
      return function(){
        var context=this, args=arguments, current=new Date();;
        clearTimeout(timer);
        if(current-begin>=duration){
           method.apply(context,args);
           begin=current;
        }else{
          timer=setTimeout(function(){
            method.apply(context,args);
          },delay);
        }
      }
    }
    复制代码

    函数防抖在underscore的实现,其基本思路,就是内部计时,达到指定时间,就执行,不然启用延时。

    复制代码
    _.debounce = function(func, wait, immediate) {
        // immediate默认为false
        var timeout, args, context, timestamp, result;
    
        var later = function() {
          // 当wait指定的时间间隔期间多次调用_.debounce返回的函数,则会不断更新timestamp的值,导致last < wait && last >= 0一直为true,从而不断启动新的计时器延时执行func
          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();
          // 第一次调用该方法时,且immediate为true,则调用func函数
          var callNow = immediate && !timeout;
          // 在wait指定的时间间隔内首次调用该方法,则启动计时器定时调用func函数
          if (!timeout) timeout = setTimeout(later, wait);
          if (callNow) {
            result = func.apply(context, args);
            context = args = null;
          }
    
          return result;
        };
      };
    复制代码

    那么应用场景:

    函数节流(throttle

    1. 频繁的mousemove/keydown,比如高频的鼠标移动,游戏射击类的

    2. 搜索联想(keyup)

    3. 进度条(我们可能不需要高频的更新进度)

    4. 拖拽的dragover等

    5.  高频的点击,抽奖等(哈哈,邪恶)

    函数防抖(debounce

     1. scroll/resize事件

     2. 文本连续输入,ajax验证/关键字搜索

    参考:

    函数节流去抖与函数柯里化

    浅谈 Underscore.js 中 _.throttle 和 _.debounce 的差异

    JS魔法堂:函数节流(throttle)与函数去抖(debounce)

     The Difference Between Throttling and Debouncing

    Javascript 函数节流和函数去抖场景介绍

  • 相关阅读:
    欧拉回路和欧拉路径
    nth_element函数
    Java读写Excel
    如何指定tomcat中session过期时间
    Java 正则表达式
    Java与模式阅读笔记(1)依赖倒转原则
    Linux vi 命令详解
    native2ascii & ascii2native
    Linux 下zip包的压缩与解压
    linux设置邮件自动转发
  • 原文地址:https://www.cnblogs.com/wangchaoyuana/p/7497377.html
Copyright © 2020-2023  润新知