博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
函数节流和函数防抖
阅读量:6817 次
发布时间:2019-06-26

本文共 4659 字,大约阅读时间需要 15 分钟。

这段时间去面试了两家当前比较拽的互联网公司,回来一总结,广度略有,深度堪忧。这么看来可能觉得还是好事,最近没事在掘金上看看,不知不觉的关注的标签已经有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的实现(解释,借用的是)

.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验证/关键字搜索

参考:

转载于:https://www.cnblogs.com/wangchaoyuana/p/7497377.html

你可能感兴趣的文章
关于数据库查询时报“query block has incorrect number of result columns”
查看>>
记录一款Unity VR视频播放器插件的开发
查看>>
webApi跨域问题
查看>>
读取文件
查看>>
json字符串转换对象的方法1
查看>>
浅谈网站路径分析 转自“蓝鲸网站分析博客”
查看>>
C# Note36: .NET unit testing framework
查看>>
我的博客第一天
查看>>
margin注意问题
查看>>
事物的回滚
查看>>
Xcode7 iOS9.0 的真机调试
查看>>
Constraint3:check约束 和 null
查看>>
Fabric 1.0环境搭建
查看>>
c冒泡排序
查看>>
第十五篇、OC_同一个View实现两个手势响应
查看>>
sql server 2008学习8 sql server存储和索引结构
查看>>
Java软件架构设计慨论
查看>>
15-用户手册(GB8567——88)
查看>>
JAVA 访问WebRoot下的目录文件
查看>>
0913数据库约束之主键 外键 非空 默认值约束 唯一约束 级联操作 表与表之间的联系...
查看>>