UDN-企业互联网技术人气社区

板块导航

浏览  : 719
回复  : 2

[原生js] 函数防抖和函数分流

[复制链接]
genie1003的头像 楼主
发表于 2017-1-9 15:39:41 | 显示全部楼层 |阅读模式
  应用场景

  我们经常需要监听滚动条滚动或者鼠标的移动,但浏览器触发这类事件的频率非常高,可能在10几毫秒就触发一次,如果我们处理事件的函数需要操作大范围的DOM,这对于浏览器的性能是个考验,可能像chrome浏览器这样优秀的浏览器会好一点,但放到老版本的IE下,就可能发生卡顿现象。有的时候,我们只需要处理函数执行一次,比如文本输入验证,执行多次处理函数反而没有必要。

  所以我们得想个办法,减少DOM操作的频度,也就是说稀释处理函数的执行频率,解决方法就是函数防抖和函数分流。函数防抖表示只执行一次处理函数,函数分流指降低处理函数的执行频率,下面是具体解释。

  函数防抖

  函数防抖指的是多次触发事件后,事件处理函数只执行一次,而且是在事件触发操作停止的时候。具体的思路就是延迟处理函数,如果设定的时间到来之前,又一次触发了事件,就清楚上一次的定时器,具体代码实现如下。
  1. var obj = document.getElementById('handle');
  2. /**
  3. * 事件触发的操作
  4. */
  5. function myFun() {
  6.     console.log('throttleV1');
  7. }
  8. /**
  9. * 不封装的方法
  10. */
  11. obj.onmousemove = function () {
  12.     clearTimeout(myFun.timer);
  13.     myFun.timer = setTimeout(myFun,50);
  14. }
复制代码

  这里有一个保存timer的技巧,如果不保存timer,那么执行完事件处理函数后,timer将被销毁,我们也就无法再清楚定时器了,所以需要保存这个变量,即使它所在的函数作用域对应的函数已经执行完了。这里用到的技巧是把timer设置为外部函数的属性,这样就不会被销毁了。

  我们还可以对这个方法进行封装。
  1. /**
  2. * 封装的方法之帮顶函数
  3. * @param method
  4. * @param delay
  5. * @param context
  6. */
  7. function debounce(method, delay, context) {
  8.     clearTimeout(method.timer);
  9.     method.timer = setTimeout(function () {
  10.         method.call(context);
  11.     },delay);
  12. }
  13. obj.onmousemove = function () {
  14.     debounce(myFun,50);
  15. };
复制代码

  这里涉及到了保存timer的技巧,总共有两个方法。

  设置为某个全局变量的属性,例如绑定到某个全局函数上,问题是如果传入了method是个匿名函数,绑定的timer就找不到了,所以这个方法有bug。
闭包 闭包的经典应用就是保留变量,下面是代码实现。
  1. ```
  2. /**
复制代码

  封装的方法之闭包

  • 闭包 如果想让一个函数执行完后,函数内的某个变量(timer)仍旧保留,就可以使用闭包
  • 把要保存的变量在父作用域声明,其他的语句放到子作用域里,并且作为一个function返回

  所以闭包可以理解为分离变量
  1. */

  2. function debounce(method,delay) {

  3. var timer=null;

  4. return function () {

  5. var context = this, args = arguments;

  6. clearTimeout(timer);

  7. timer = setTimeout(function () {

  8. method.apply(context,args);

  9. },delay);

  10. }

  11. }

  12. obj.onmousemove = debounce(myFun,50);
复制代码

  ##函数分流

  函数分流的思想就是计时,上面的代码是只有在操作结束后才执行,只需要在上面的代码上加一个计时判断,如果操作了设定的时间,就执行一次处理函数,就达到了分流的效果。
  1. /**
  2. 函数节流throttle
  3. @param 事件触发的操作
  4. @param 延迟执行函数的时间
  5. @param 超过多长时间必须执行一次函数
  6. @returns {Function}

  7. */

  8. function throttle(method, delay, mustRunDelay) {

  9. var timer = null, args = arguments;

  10. var start = 0, now = 0;

  11. return function () {

  12. var context = this;

  13. now= Date.now();

  14. if(!start){

  15. start = now;

  16. }

  17. if(now - start >= mustRunDelay){

  18. method.apply(context, args);

  19. start = Date.now();

  20. }else {

  21. clearTimeout(timer);

  22. timer = setTimeout(function () {

  23. method.apply(context, args);

  24. }, delay);

  25. }

  26. }

  27. }

  28. obj.onmousemove = throttle(myFun, 50, 500);

  29. ```
复制代码

  总结 

  函数防抖和函数分流的思想都是通过定时器控制函数的执行频率。

  参考目录

  • http://www.alloyteam.com/2012/11/JavaScript-throttle/
  • http://web.jobbole.com/88306/
  • https://github.com/hanzichi/underscore-analysis/issues/21
  • https://github.com/hanzichi/underscore-analysis/issues/22

相关帖子

发表于 2017-1-9 15:40:10 | 显示全部楼层
我完全是被标题<<函数防抖和函数分流>>吸引过来的
使用道具 举报

回复

发表于 2017-1-9 15:40:12 来自手机 | 显示全部楼层
LZ是闲人,天天发帖,坚定完毕
使用道具 举报

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部