当前位置: 首页 > 编程日记 > 正文

throttle与debounce的区别

前几天看到一篇文章,我的公众号里也分享了《一次发现underscore源码bug的经历以及对学术界拿来主义的思考》具体文章详见,微信公众号:
图片描述
文中讲了大家对throttle和debounce存在误解,同时提到了《高程3》中实现节流方法存在一些问题,为了更好的理解这两个概念,搜了很多相关文章,详见文章底部。

throttle与debounce是两个类似的概念,目的都是随着时间的推移控制执行函数的次数,但是有些细微的差别。

当我们为DOM事件关联方法时,若我们有一个debounced和throttled函数将会很方便,为何?因为这样我们可以在事件和执行函数之间添加一层控制,注意我们并没有去控制DOM事件触发的次数。

例如,我们谈一下scroll事件,看下面的例子:

<p data-height="268" data-theme-id="0" data-slug-hash="xVpoOe" data-default-tab="result" data-user="ghostcode" class="codepen">See the Pen Scroll events counter by ghostcode (@ghostcode) on CodePen.</p>

当你在触控板或者鼠标滚动时,每次最少会达到30次,在手机上更多。可是你的滚动事件处理函数对这个频率是否应付的过来?

在2011年,Twitter网站曾爆出一个问题:当你在主页往下滚动时,页面会变得缓慢以致没有响应。John Resig发表了一篇文章《 a blog post about the problem》指出直接在scroll事件上面绑定高消耗的事件是一个多么愚蠢的想法。

在那个时候John建议使用一个独立于scroll事件且每250ms执行的轮询方法。这样的话处理方法就不会耦合于事件。通过这个简单的技术,我们可以提高用户体验。

现在有一些更先进的事件处理方法,让我来给你介绍:__Debounce,Throttle和requestAnimationFrame__,同时会介绍一些适用的场景。

Debounce

Debounce技术使我们可以将一个连续的调用归为一个。

图片描述

想象你在电梯的场景,当电梯门开始要关闭的时候,突然一个人进来,此时电梯并不会关闭并且也不会执行改变楼层的方法,如果还有人进来同样的事情会发生:电梯延迟执行它的方法(改变楼层),优化了它的资源。

自己尝试一下,在按钮上点击或者移动鼠标:

<p data-height="268" data-theme-id="0" data-slug-hash="vGpqLO" data-default-tab="result" data-user="ghostcode" class="codepen">See the Pen Debounce. Trailing by ghostcode (@ghostcode) on CodePen.</p>

你可以看到快速连续的事件是如何通过一个debounce事件来表示的。

Leading edge (or "immediate")

你可以发现事件结束的时候,debounce的事件并没有立即执行而是等待了一些时间才触发。为何不立即触发,就像开始没有使用debounce事件处理?直到在连续执行的事件中有一个暂停,才会再次触发。

你可以通过一个__leading__的参数做到:

图片描述

在underscore.js中,这个参数叫immediate。

自己尝试一下:

<p data-height="268" data-theme-id="0" data-slug-hash="VaQwRm" data-default-tab="result" data-user="ghostcode" class="codepen">See the Pen Debounce. Leading by ghostcode (@ghostcode) on CodePen.</p>

Debounce Implementations

2009年在John Hann的文章中第一次看到debounce的实现方法。

在那之后不久,Ben Alman写了一个jQuery插件(现在不在维护),一年以后Jeremy Ashkenas把此方法添加到underscore.js中,不久又被添加到lodash中。

<p data-height="268" data-theme-id="0" data-slug-hash="GZQRLv" data-default-tab="result" data-user="ghostcode" class="codepen">See the Pen debounce-click by ghostcode (@ghostcode) on CodePen.</p>

这三种实现方法内部不同,但是接口几乎一致。

有段时间underscore采用了Lodash的实现方法,但是在我发现了一个bug之后,自此两个库的实现开始分道扬镳。

Lodash在_.debounce和_.throttle中添加了许多特性。immediate标示替代了leading和trailing。你可以二选一或者都选,默认情况下,只有trailing是开启的。

Debounce Examples

当改变浏览器窗口时,resize事件会触发多次。

<p data-height="268" data-theme-id="0" data-slug-hash="PNQorE" data-default-tab="result" data-user="ghostcode" class="codepen">See the Pen Debounce Resize Event Example by ghostcode (@ghostcode) on CodePen.</p>

如你所见,我们使用了__trailing__参数,因为我们只对用户停止改变浏览器大小时最后一次事件感兴趣。

AutoComplete中的Ajax请求使用的keypress

当用户仍旧在输入的时候,为何每隔50ms发送Ajax请求?__ _.debounce __可以帮助我们避免额外的工作,只在用户停止输入的时候发送请求。

<p data-height="268" data-theme-id="0" data-slug-hash="wGyvVj" data-default-tab="result" data-user="ghostcode" class="codepen">See the Pen Debouncing keystrokes Example by ghostcode (@ghostcode) on CodePen.</p>

另一个使用场景是在进行input校验的时候,“你的密码太短”等类似的信息。

如何使用debounce和throttle以及常见的陷阱?

可以自己实现这两个方法或者随便复制别人blog中的实现方法,我的建议是直接使用underscore和lodash中的方法。如果你只需要这两个方法,可以定制输出lodash方法:

npm i -g lodash-cli
lodash-cli include=debounce,throttle

一个常见的陷阱:

// WRONG
$(window).on('scroll', function() {_.debounce(doSomething, 300); 
});// RIGHT
$(window).on('scroll', _.debounce(doSomething, 200));

debounce方法赋值给一个变量之后允许我们调用一个私有方法:__debounced_version.cancel()__:

var debounced_version = _.debounce(doSomething, 200);
$(window).on('scroll', debounced_version);// If you need it
debounced_version.cancel();

Throttle

使用__ _.throttle __,我们不允许方法在每Xms间执行超过一次。

和debounce的主要区别是throttle保证方法每Xms有规律的执行。

Throttling Examples

一个相当常见的例子,用户在你无限滚动的页面上向下拖动,你需要判断现在距离页面底部多少。如果用户快接近底部时,我们应该发送请求来加载更多内容到页面。

在此__ _.debounce 没有用,因为它只会在用户停止滚动时触发,但我们需要用户快到达底部时去请求。通过 _.throttle __我们可以不间断的监测距离底部多远。

<p data-height="268" data-theme-id="0" data-slug-hash="xVYbGZ" data-default-tab="result" data-user="ghostcode" class="codepen">See the Pen Infinite scrolling throttled by ghostcode (@ghostcode) on CodePen.</p>

requestAnimationFrame (rAF)

requestAnimationFrame是另一个频率限制的方法。

它可以通过__ _.throttle(dosomething, 16)__实现,但为了更加精准浏览器提供了内置API。

我们可以使用rAF API作为throttle方法的替代,考虑一下利弊:

利:

  • 目标60fps(16ms每贞),但是内部使用最优的时间间隔来渲染
  • 使用简单并且是标准API,以后不会变动,不需要维护

弊:

  • rAF的开始或者取消需要我们自己处理,不像.debounce和.throttle内部实现
  • 浏览器Tag没有激活,它就不会执行
  • 即使多数现代浏览器支持,但是IE9,Opera Mini以及老版本Android依旧不支持。A polyfill到现在依旧需要
  • rAF在node.js中不支持

根据经验,我建议在JS执行"painting"或"animating"中直接操作属性和重新计算元素位置时使用rAF。

发送Ajax请求或者是否添加/删除class(触发一个CSS动画)时,我会考虑debounce和throttle,此时你可以降低执行频率(200ms而不是16ms)。

rAF的例子

在Paul Lewis的文章激发下,我只在scroll事件中提供例子。

我一步步的调throttle到16ms,希望给一个类似的体验,但是rAF在复杂场景下或许会提供更好的结果。

<p data-height="268" data-theme-id="0" data-slug-hash="qZxEaq" data-default-tab="result" data-user="ghostcode" class="codepen">See the Pen Scroll comparison requestAnimationFrame vs throttle by ghostcode (@ghostcode) on CodePen.</p>

一个更好的例子我是在headroom.js中看到的,这里通过一个对象封装,进行了逻辑解藕。

总结:
使用debounce,throttle和requestAnimationFrame优化你的事件处理函数。每一个方法有一些细微的差别,三个都很有用而且互相弥补。

  • __debounce:__把突然涌进的事件(键盘事件)归位一个
  • __throttle:__保证持续执行方法分隔为每Xms执行一次。就像每200ms监测滚动位置来触发css动画。
  • __requestAnimationFrame:__throttle的替代方案,当你的方法需要重新计算和渲染元素同时你需要更平滑的变动或动画。注意:IE9- 不支持。
  1. https://blog.coding.net/blog/...
  2. https://css-tricks.com/the-di...
  3. http://stackoverflow.com/ques...
  4. http://demo.nimius.net/deboun...

相关文章:

Spring源码分析【0】-框架的基础:继承和接口调用链

Spring源码大量的使用继承和接口调用&#xff0c;现举个例子&#xff0c;不搞清楚这个无法看代码。 public class A extends B{public void f1() {System.out.println("f1 in a");} }public abstract class B extends C {protected abstract void f1();protected Str…

华人计算机视觉科学家黄煦涛逝世,众多AI大牛发文缅怀

当地时间2020年4月25日&#xff0c;华人计算机科学家黄煦涛教授在美国印第安纳州逝世&#xff0c;享年84岁。黄煦涛教授主要从事教学与图像处理、模式识别、计算机视觉和人机交互等方面的研究工作&#xff0c;一生出版了 14 本书&#xff0c;发表了 400 多篇学术论文。在学术研…

七年之痒,再见理想

不确定“再见理想”是“再见了&#xff0c;理想”还是“再次燃起理想”&#xff0c;稀里糊涂地对这句话有感觉。作为程序员&#xff0c;总会有自己的技术价值观和技术理想。工作七年多&#xff0c;开始痒了。 程序员的生活总是喜忧参半&#xff0c;出入体面的写字楼&#xff0c…

HTML5学习笔记二 HTML基础

一、HTML 标题 HTML 标题&#xff08;Heading&#xff09;是通过<h1> - <h6> 标签来定义的. <h1>标题一</h1> <h2>标题二</h2> <h3>标题三</h3> 二、HTML 段落 HTML 段落是通过标签 <p> 来定义的. <p>亲吻你的手还…

程序员感叹一年只能存下15万太少了……网友:潸然泪下

最近有程序员网友晒出自己的年终奖&#xff0c;税后高达15.7万&#xff01;看到这个情形&#xff0c;很多网友表示自己“被打鸡血了”。他强调学习的重要性&#xff0c;学习仍然是在这个时代下&#xff0c;普通人能够逆袭&#xff0c;给家人更好生活的一把利器&#xff01;今天…

Spring源码分析【2】-Tomcat和Sping的连接点

Tomcat是怎么调用上Spring的呢&#xff1f;需要找到这个连接点。 答案就在org.apache.catalina.startup.ContextConfig的processServletContainerInitializers方法 new WebappServiceLoader() 回到processServletContainerInitializers 进入org.apache.catalina.startup.Weba…

优化数据库的方法及SQL语句优化的原则

优化数据库的方法&#xff1a; 1、关键字段建立索引。 2、使用存储过程&#xff0c;它使SQL变得更加灵活和高效。 3、备份数据库和清除垃圾数据。 4、SQL语句语法的优化。&#xff08;可以用Sybase的SQL Expert&#xff0c;可惜我没找到unexpired的序列号&#xff09; 5、清理删…

各大浏览器 CSS3 和 HTML5 兼容速查表

2019独角兽企业重金招聘Python工程师标准>>> 不知不觉中&#xff0c;支持 CSS3 和 HTML5 的浏览器变得越来越多&#xff0c;甚至包括最新版的 IE&#xff0c;当然&#xff0c;所谓支持仅仅是部分支持&#xff0c;因为 CSS3 和 HTML5 的W3C 规范都尚未形成。如果你现…

Spring源码分析【1】-Tomcat的初始化

org.apache.catalina.startup.ContextConfig.configureStart() org.apache.catalina.startup.ContextConfig.webConfig() 进入org.apache.catalina.startup.ContextConfig.processServletContainerInitializers processServletContainerInitializers参考&#xff1a;Spring源…

360金融首席科学家张家兴:只靠AI Lab做不好AI中台 | 独家专访

「AI 技术生态论」 人物访谈栏目是 CSDN 发起的百万人学 AI 倡议下的重要组成部分。通过对 AI 生态顶级大咖、创业者、行业 KOL 的访谈&#xff0c;反映其对于行业的思考、未来趋势判断、技术实践&#xff0c;以及成长经历。 本文为 「AI 技术生态论」系列访谈第21期&#xff0…

Delphi 正则表达式语法(3): 匹配范围

// [A-Z]: 匹配所有大写字母var reg: TPerlRegEx; begin reg : TPerlRegEx.Create(nil); reg.Subject : CodeGear Delphi 2007 for Win32; reg.RegEx : [A-Z]; reg.Replacement : ◆; reg.ReplaceAll; ShowMessage(reg.Subject); //返回: ◆ode◆ear ◆elphi 200…

基础算法整理(1)——递归与递推

程序调用自身的编程技巧称为递归&#xff08; recursion&#xff09;。递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法&#xff0c;它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解&…

php正则表达式函数 preg_replace用法

preg_replace (PHP 3> 3.0.9, PHP 4 ) preg_replace -- 执行正则表达式的搜索和替换说明 mixedpreg_replace( mixed pattern, mixed replacement, mixed subject [, int limit])在 subject 中搜索 pattern 模式的匹配项并替换为 replacement。如果指定了 limit&#xff0c;则…

面试官吐槽:“Python程序员就是不行!”网友:我能把你面哭!

最近几年&#xff0c;Python莫名火了起来&#xff0c;很多公司都想赶上这“莫名”的热潮&#xff0c;招聘到大牛人才。但是&#xff0c;最近一个HR在社交网站的吐槽又火了&#xff1a;那么问题来了&#xff0c;市面上为什么鲜有企业满意的优秀的Python程序员&#xff1f;企业到…

Spring源码分析【5】-Spring MVC处理流程

org.apache.catalina.core.ApplicationFilterChain.doFilter 获取Filter org.apache.catalina.core.ApplicationFilterChain.internalDoFilter org.springframework.web.filter.DelegatingFilterProxy.doFilter invokeDelegate org.springframework.security.web.FilterCha…

Mysql——外键

2019独角兽企业重金招聘Python工程师标准>>> 一&#xff0c;外键 外键&#xff1a;foreign key&#xff0c;&#xff08;外边的键&#xff0c;键不在本表中&#xff09;&#xff1a;如果一张表中有一个字段&#xff08;非主键&#xff09;指向另一张表的主键&#x…

揭开「拓扑排序」的神秘面纱

作者 | 小齐本齐责编 | Carol来源 | 码农田小齐Topological sort 又称 Topological order&#xff0c;这个名字有点迷惑性&#xff0c;因为拓扑排序并不是一个纯粹的排序算法&#xff0c;它只是针对某一类图&#xff0c;找到一个可以执行的线性顺序。这个算法听起来高大上&…

Spring源码分析【6】-ThreadLocal的使用和源码分析

Spring代码使用到了ThreadLocal java.lang.ThreadLocal.set getMap java.lang.Thread.threadLocals定义 回到set 如果map为null 则createMap

《软件的破解》

本人根据自己的经验简单给大家谈一谈。这些问题对于初学者来说常常是很需要搞明白的&#xff0c;根据我自己的学习经历&#xff0c;如果你直接照着很多破解教程去学习的话&#xff0c;多半都会把自己搞得满头的雾水&#xff0c;因为有很多的概念要么自己不是很清楚&#xff0c;…

php级别鉴定

一、PHP初级程序员薪资水平&#xff1a;4000.00--8000.00&#xff08;RMB/月&#xff09;~HTML设计与应用~DIVCSS~PHP基础~MySQL基础~PHP高级~CMS系统二、PHP中级程序员 薪资水平&#xff1a;8000.00--12000.00&#xff08;RMB/月&#xff09;~PHP面向对象~MySQL高级~Smarty模板…

Spring源码分析【7】-Spring 模板页和JSP文件的编译

org.apache.jasper.servlet.JspServletWrapper.service org.apache.jasper.JspCompilationContext.compile org.apache.jasper.JspCompilationContext.createCompiler org.apache.jasper.compiler.Compiler.isOutDated 判断文件是否存在 ..\Apache\apache-tomcat-8.0.36\w…

Distinction Between Strategy and Decorator

首先看Strategy和Decorator在GoF的《Design Patterns》的intent Decorator (1)intent: Attach additional responsibilities to an object dynamically.Decorators provide a flexible alternative to subclassing for extending functionality. (2)UML Diagram: Strategy (1)i…

我竟然混进了Python高级圈子!

现如今&#xff0c;计算机科学、人工智能、数据科学已成为技术发展的主要推动力。无论是要翻阅这些领域的文章&#xff0c;还是要参与相关任务&#xff0c;你马上就会遇到一些拦路虎&#xff1a;想过滤垃圾邮件&#xff0c;不具备概率论中的贝叶斯思维恐怕不行&#xff1b;想试…

unity3d中旋转

自转是Rotate&#xff0c;绕转是RotateAround&#xff0c;LookAt旋转物体自身&#xff0c;使其正面朝向目标点以上操作都在transform中完成转载于:https://blog.51cto.com/568464209/1764050

Java常用方法

1. 把Strings转换成int和把int转换成StringString a String.valueOf(2); //integer to numeric string int i Integer.parseInt(a); //numeric string to an int String a String.valueOf(2); //integer to numeric stringint i Integer.parseInt(a); //numeric string …

request.getSession(false)到底返回什么

HttpSession session request.getSession(false); 很明显传false如果session不存在返回Null。

洞察疫情,微软推出新冠数据分析网站COVID Insights

来源 | 微软研究院AI头条COVID Insights 网站功能亮点持续数月的新冠疫情一路肆虐、席卷全球&#xff0c;世界各地的科研人员都在为此奋战&#xff0c;希望通过最先进的技术逐步揭开新冠病毒的神秘面纱。近日&#xff0c;微软亚洲研究院的研究人员基于在计算生物学、数据分析等…

LINUX 查找tomcat日志关键词

#查询catalina.out日志文件中的关键词为2016-04-13 11:26:00的日志信息grep -C 10 2016-04-13 11:26:00 catalina.out |more解释&#xff1a;grep &#xff1a;查询&#xff0c;筛选-C &#xff1a; grep的-A, -B, -C选项分别可以显示匹配行的后,前,后前多少行内容:10 &#xf…

转帖 javascript事件监听

原帖地址&#xff1a; http://www.cnblogs.com/AganCN/archive/2008/05/24/1206272.html 考虑这样的情形在IE浏览中处理&#xff0c;需要响应页面的按钮点击事件&#xff0c;有哪些方法呢&#xff1f;&#xff08;1&#xff09;onclick属性添加事件处理函数 <javascript>…

推荐系统发展的六大影响因子 | 深度

作者丨gongyouliu来源 | 大数据与人工智能&#xff08;ID: ai-big-data&#xff09;随着科学技术的进步&#xff0c;移动互联网快速发展&#xff0c;手机越来越便宜&#xff0c;拥有智能手机不再是一件遥不可及的事情&#xff0c;互联网用户规模已接近增长的顶点。摄像头和信息…