JavaScript-性能优化之函数节流(throttle)与函数去抖(debounce)
        函数节流,简单地讲,就是让一个函数无法在很短的时间间隔内连续调用,只有当上一次函数执行后过了你规定的时间间隔,才能进行下一次该函数的调用。
        函数节流的原理挺简单的,估计大家都想到了,那就是定时器。当我触发一个时间时,先setTimout让这个事件延迟一会再执行,如果在这个时间间隔内又触发了事件,那我们就clear掉原来的定时器,再setTimeout一个新的定时器延迟一会执行,就这样。
以下场景往往由于事件频繁被触发,因而频繁执行DOM操作、资源加载等重行为,导致UI停顿甚至浏览器崩溃。
  1. window对象的resize、scroll事件
  2. 拖拽时的mousemove事件
  3. 射击游戏中的mousedown、keydown事件
  4. 文字输入、自动完成的keyup事件
          实际上对于window的resize事件,实际需求大多为停止改变大小n毫秒后执行后续处理;而其他事件大多的需求是以一定的频率执行后续处理。针对这两种需求就出现了debounce和throttle两种解决办法。
throttle 和 debounce 是解决请求和响应速度不匹配问题的两个方案。二者的差异在于选择不同的策略。
        throttle 等时间 间隔执行函数。
        debounce 时间间隔 t 内若再次触发事件,则重新计时,直到停止时间大于或等于 t 才执行函数。
一、throttle函数的简单实现
  1. function throttle(fn, threshhold, scope) {
  2. threshhold || (threshhold = 250);
  3. var last,
  4. timer;
  5. return function () {
  6. var context = scope || this;
  7. var now = +new Date(),
  8. args = arguments;
  9. if (last && now - last + threshhold < 0) {
  10. // hold on to it
  11. clearTimeout(deferTimer);
  12. timer = setTimeout(function () {
  13. last = now;
  14. fn.apply(context, args);
  15. }, threshhold);
  16. } else {
  17. last = now;
  18. fn.apply(context, args);
  19. }
  20. };
  21. }

调用方法

$('body').on('mousemove', throttle(function (event) {
  console.log('tick');
}, 1000));
二、debounce函数的简单实现
  1. function debounce(fn, delay) {
  2. var timer = null;
  3. return function () {
  4. var context = this, args = arguments;
  5. clearTimeout(timer);
  6. timer = setTimeout(function () {
  7. fn.apply(context, args);
  8. }, delay);
  9. };
  10. }

调用方法

$('input.username').keypress(debounce(function (event) {
  // do the Ajax request
}, 250));
三、简单的封装实现
  1. /**
  2. * throttle
  3. * @param fn, wait, debounce
  4. */
  5. var throttle = function ( fn, wait, debounce ) {
  6. var timer = null, // 定时器
  7. t_last = null, // 上次设置的时间
  8. context, // 上下文
  9. args, // 参数
  10. diff; // 时间差
  11. return funciton () {
  12. var curr = + new Date();
  13. var context = this, args = arguments;
  14. clearTimeout( timer );
  15. if ( debounce ) { // 如果是debounce
  16. timer = setTimeout( function () {
  17. fn.apply( context, args );
  18. }, wait );
  19. } else { // 如果是throttle
  20. if ( !t_last ) t_last = curr;
  21. if ( curr - t_last &gt;= wait ) {
  22. fn.apply( context, wait );
  23. context = wait = null;
  24. }
  25. }
  26. }
  27. }
  28. /**
  29. * debounce
  30. * @param fn, wait
  31. */
  32. var debounce = function ( fn, wait ) {
  33. return throttle( fn, wait, true );
  34. }
小结:这两个方法适用于会重复触发的一些事件,如:mousemove,keydown,keyup,keypress,scroll等。如果只绑定原生事件,不加以控制,会使得浏览器卡顿,用户体验差。为了提高js性能,建议在使用以上及类似事件的时候用函数节流或者函数去抖加以控制。
四、underscore v1.7.0相关的源码剖析                          
1. _.throttle函数
  1. _.throttle = function(func, wait, options) {
  2. var context, args, result;
  3. var timeout = null; // 定时器
  4. var previous = 0; // 上次触发的时间
  5. if (!options) options = {};
  6. var later = function() {
  7. previous = options.leading === false ? 0 : _.now();
  8. timeout = null;
  9. result = func.apply(context, args);
  10. if (!timeout) context = args = null;
  11. };
  12. return function() {
  13. var now = _.now();
  14.  
  15. // 第一次是否执行
  16. if (!previous &amp;&amp; options.leading === false) previous = now;
  17.  
  18. // 这里引入了一个remaining的概念:还剩多长时间执行事件
  19. var remaining = wait - (now - previous);
  20. context = this;
  21. args = arguments;
  22. // remaining &lt;= 0 考虑到事件停止后重新触发或者
  23. // 正好相差wait的时候,这些情况下,会立即触发事件
  24. // remaining &gt; wait 没有考虑到相应场景
  25. // 因为now-previous永远都是正值,且不为0,那么
  26. // remaining就会一直比wait小,没有大于wait的情况
  27. // 估计是保险起见吧,这种情况也是立即执行
  28. if (remaining &lt;= 0 || remaining &gt; wait) {
  29. if (timeout) {
  30. clearTimeout(timeout);
  31. timeout = null;
  32. }
  33. previous = now;
  34. result = func.apply(context, args);
  35. if (!timeout) context = args = null;
  36.  
  37. // 是否跟踪
  38. } else if (!timeout &amp;&amp; options.trailing !== false) {
  39. timeout = setTimeout(later, remaining);
  40. }
  41. return result;
  42. };
  43. };
  1. 由上可见,underscore考虑了比较多的情况:
    options.leading 第一次是否执行,默认为true,表示第一次会执行,传入{leading:false}则禁用第一次执行
    options.trailing:最后一次是否执行,默认为true,表示最后一次会执行,传入{trailing: false}表示最后一次不执行
    所谓第一次是否执行,是刚开始触发事件时,要不要先触发事件,如果要,则previous=0remaining 为负值,则立即调用了函数
    所谓最后一次是否执行,是事件结束后,最后一次触发了此方法,如果要执行,则设置定时器,即事件结束以后还要在执行一次。
    remianing > wait 表示客户端时间被修改过。
2. _.debounce函数 
  1. _.debounce = function(func, wait, immediate) {
  2. // immediate默认为false
  3. var timeout, args, context, timestamp, result;
  4. var later = function() {
  5. // 当wait指定的时间间隔期间多次调用_.debounce返回的函数,则会不断更新timestamp的值,导致last < wait && last >= 0一直为true,从而不断启动新的计时器延时执行func
  6. var last = _.now() - timestamp;
  7. if (last < wait && last >= 0) {
  8. timeout = setTimeout(later, wait - last);
  9. } else {
  10. timeout = null;
  11. if (!immediate) {
  12. result = func.apply(context, args);
  13. if (!timeout) context = args = null;
  14. }
  15. }
  16. };
  17. return function() {
  18. context = this;
  19. args = arguments;
  20. timestamp = _.now();
  21. // 第一次调用该方法时,且immediate为true,则调用func函数
  22. var callNow = immediate && !timeout;
  23. // 在wait指定的时间间隔内首次调用该方法,则启动计时器定时调用func函数
  24. if (!timeout) timeout = setTimeout(later, wait);
  25. if (callNow) {
  26. result = func.apply(context, args);
  27. context = args = null;
  28. }
  29. return result;
  30. };
  31. };
  1. _.debounce实现的精彩之处我认为是通过递归启动计时器来代替通过调用clearTimeout来调整调用func函数的延时执行。
参考链接:

(转)JavaScript-性能优化之函数节流(throttle)与函数去抖(debounce)的更多相关文章

  1. [JavaScript] 函数节流(throttle)和函数防抖(debounce)

    js 的函数节流(throttle)和函数防抖(debounce)概述 函数防抖(debounce) 一个事件频繁触发,但是我们不想让他触发的这么频繁,于是我们就设置一个定时器让这个事件在 xxx 秒 ...

  2. javascript 函数节流 throttle 解决函数被频繁调用、浏览器卡顿的问题

    * 使用setTimeout index.html <html> <head> <meta charset="UTF-8"> <title ...

  3. JS中的函数节流throttle详解和优化

    JS中的函数节流throttle详解和优化在前端开发中,有时会为页面绑定resize事件,或者为一个页面元素绑定拖拽事件(mousemove),这种事件有一个特点,在一个正常的操作中,有可能在一个短的 ...

  4. JavaScript性能优化

    如今主流浏览器都在比拼JavaScript引擎的执行速度,但最终都会达到一个理论极限,即无限接近编译后程序执行速度. 这种情况下决定程序速度的另一个重要因素就是代码本身. 在这里我们会分门别类的介绍J ...

  5. 摘:JavaScript性能优化小知识总结

    原文地址:http://www.codeceo.com/article/javascript-performance-tips.html JavaScript的性能问题不容小觑,这就需要我们开发人员在 ...

  6. JavaScript性能优化小窍门汇总(含实例)

    在众多语言中,JavaScript已经占有重要的一席之地,利用JavaScript我们可以做很多事情 , 应用广泛.在web应用项目中,需要大量JavaScript的代码,将来也会越来越多.但是由于J ...

  7. js 函数节流throttle 函数去抖debounce

    1.函数节流throttle 通俗解释: 假设你正在乘电梯上楼,当电梯门关闭之前发现有人也要乘电梯,礼貌起见,你会按下开门开关,然后等他进电梯: 但是,你是个没耐心的人,你最多只会等待电梯停留一分钟: ...

  8. JavaScript性能优化小知识总结(转)

    JavaScript的性能问题不容小觑,这就需要我们开发人员在编写JavaScript程序时多注意一些细节,本文非常详细的介绍了一下JavaScript性能优化方面的知识点,绝对是干货. 前言 一直在 ...

  9. JavaScript性能优化篇js优化

    JavaScript性能优化篇js优化   随着Ajax越来越普遍,Ajax引用的规模越来越大,Javascript代码的性能越来越显得重要,我想这就是一个很典型的例子,上面那段代码因为会被频繁使用, ...

  10. 函数节流throttle和防抖debounce

    throttle 函数节流 不论触发函数多少次,函数只在设定条件到达时调用第一次函数设定,函数节流 1234567891011 let throttle = function(fn,intervalT ...

随机推荐

  1. ZooKeeper官方文档翻译——ZooKeeper Overview 3.4.6

    ZooKeeper ZooKeeper: A Distributed Coordination Service for Distributed Applications (针对分布式应用的分布式调度服 ...

  2. Spring MVC 学习总结(二)——控制器定义与@RequestMapping详解

    一.控制器定义 控制器提供访问应用程序的行为,通常通过服务接口定义或注解定义两种方法实现. 控制器解析用户的请求并将其转换为一个模型.在Spring MVC中一个控制器可以包含多个Action(动作. ...

  3. NASA的下一个十年(译)

    原文 MICHAEL ROSTON (New York Times) 从左起:木卫二:土卫六:经过火星的水手谷星的合成图:金星的拼接图 大多数人已经从人类第一次近距离看到冥王星的兴奋中冷静下来.下一个 ...

  4. No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?

    以前用MyEclipse,现在用eclipse配置maven后,运行run install.报错: [ERROR] No compiler is provided in this environmen ...

  5. 16个时髦的扁平化设计的 HTML5 & CSS3 网站模板

    创建网站最好办法之一是使用现成的网站模板或使用开源 CMS 应用程序.所以,今天这篇文章给大家带来的是16款基于 HTML5 & CSS3 的精美的扁平风格网站模板,大家可以借助这些优秀的网站 ...

  6. JS魔法堂:从void 0 === undefined说起

    一.前言 当使用coffeescript书写如下代码时 name = person?.name 会被预编译为 ; ,那么void 0到底是什么意思呢?运行得知void 0===undefined为tr ...

  7. iOS开发的一些奇巧淫技

    TableView不显示没内容的Cell怎么办? 类似这种,我不想让下面那些空的显示. 很简单. self.tableView.tableFooterView = [[UIView alloc] in ...

  8. JavaScript的setTimeout和setInterval的深入理解

    发表过一片博客<跟着我用JavaScript写计时器>,比较基础.....有网友说应该写一下setTimeout的原理和机制,嗯,今天就来写一下吧: 直奔主题:setTimeout和set ...

  9. 需要正确安装 Microsoft.Windows.ShellExperienceHost 和 "Microsoft.Windows.Cortana" 应用程序。

    windows 10 开始菜单修复工具 Win10开始菜单修复工具出现的原因,自从升级到Windows  10,一直BUG不断,而其中有一个BUG非常的让你印象深刻,就是开始菜单无响应,你用着用着电脑 ...

  10. jquery 进阶

    1.0 jquery的ajax同步和异步区别 2.0 cdnjquery加载失败加载本地 <script type="text/javascript" src="/ ...