Debounce 和 Throttle 的原理及实现---防止频繁触发某事件
原文:http://blog.csdn.net/redtopic/article/details/69396722
在处理诸如 resize
、scroll
、mousemove
和 keydown/keyup/keypress
等事件的时候,通常我们不希望这些事件太过频繁地触发,尤其是监听程序中涉及到大量的计算或者有非常耗费资源的操作。
有多频繁呢?以 mousemove
为例,根据 DOM Level 3 的规定,「如果鼠标连续移动,那么浏览器就应该触发多个连续的 mousemove
事件」,这意味着浏览器会在其内部计时器允许的情况下,根据用户移动鼠标的速度来触发 mousemove
事件。(当然了,如果移动鼠标的速度足够快,比如“刷”一下扫过去,浏览器是不会触发这个事件的)。resize
、scroll
和 key*
等事件与此类似。
可以参看这个 Demo 体会下。
Debounce
DOM 事件里的 debounce
概念其实是从机械开关和继电器的“去弹跳”(debounce)衍生 出来的,基本思路就是把多个信号合并为一个信号。这篇文章 解释得非常清楚,感兴趣的可以一读。
在 JavaScript 中,debounce
函数所做的事情就是,强制一个函数在某个连续时间段内只执行一次,哪怕它本来会被调用多次。我们希望在用户停止某个操作一段时间之后才执行相应的监听函数,而不是在用户操作的过程当中,浏览器触发多少次事件,就执行多少次监听函数。
比如,在某个 3s 的时间段内连续地移动了鼠标,浏览器可能会触发几十(甚至几百)个 mousemove
事件,不使用 debounce
的话,监听函数就要执行这么多次;如果对监听函数使用 100ms 的“去弹跳”,那么浏览器只会执行一次这个监听函数,而且是在第 3.1s 的时候执行的。
现在,我们就来实现一个 debounce
函数。
实现
我们这个 debounce
函数接收两个参数,第一个是要“去弹跳”的回调函数 fn
,第二个是延迟的时间 delay
。
实际上,大部分的完整
debounce
实现还有第三个参数immediate
,表明回调函数是在一个时间区间的最开始执行(immediate
为true
)还是最后执行(immediate
为false
),比如 underscore 的 _.debounce。本文不考虑这个参数,只考虑最后执行的情况,感兴趣的可以自行研究。
1 |
/** |
其实思路很简单,debounce
返回了一个闭包,这个闭包依然会被连续频繁地调用,但是在闭包内部,却限制了原始函数 fn
的执行,强制 fn
只在连续操作停止后只执行一次。
debounce
的使用方式如下:
1 |
$(document).on('mouvemove', debounce(function(e) { |
用例
还是以 mousemove
为例,为其绑定一个“去弹跳”的监听器,效果是怎样的?请看这个 Demo。
再来考虑另外一个场景:根据用户的输入实时向服务器发 ajax 请求获取数据。我们知道,浏览器触发 key*
事件也是非常快的,即便是正常人的正常打字速度,key*
事件被触发的频率也是很高的。以这种频率发送请求,一是我们并没有拿到用户的完整输入发送给服务器,二是这种频繁的无用请求实在没有必要。
更合理的处理方式是,在用户“停止”输入一小段时间以后,再发送请求。那么 debounce
就派上用场了:
1 |
$('input').on('keyup', debounce(function(e) { |
可以查看这个 Demo 看看效果。
Throttle
throttle
的概念理解起来更容易,就是固定函数执行的速率,即所谓的“节流”。正常情况下,mousemove
的监听函数可能会每 20ms(假设)执行一次,如果设置 200ms 的“节流”,那么它就会每 200ms 执行一次。比如在 1s 的时间段内,正常的监听函数可能会执行 50(1000/20) 次,“节流” 200ms 后则会执行 5(1000/200) 次。
我们先来看 Demo。可以看到,不管鼠标移动的速度是慢是快,“节流”后的监听函数都会“匀速”地每 250ms 执行一次。
实现
与 debounce
类似,我们这个 throttle
也接收两个参数,一个实际要执行的函数 fn
,一个执行间隔阈值 threshhold
。
同样的,
throttle
的更完整实现可以参看 underscore 的 _.throttle。
1 |
/** |
原理也不复杂,相比 debounce
,无非是多了一个时间间隔的判断,其他的逻辑基本一致。throttle
的使用方式如下:
1 |
$(document).on('mouvemove', throttle(function(e) { |
用例
throttle
常用的场景是限制 resize
和 scroll
的触发频率。以 scroll
为例,查看这个 Demo 感受下。
可视化解释
如果还是不能完全体会 debounce
和 throttle
的差异,可以到 这个页面 看一下两者可视化的比较。
总结
debounce
强制函数在某段时间内只执行一次,throttle
强制函数以固定的速率执行。在处理一些高频率触发的 DOM 事件的时候,它们都能极大提高用户体验。
Debounce 和 Throttle 的原理及实现---防止频繁触发某事件的更多相关文章
- debounce 与 throttle 区别
原文地址:http://undefinedblog.com/debounce-and-throttle/ 二.什么是debounce 1. 定义 如果用手指一直按住一个弹簧,它将不会弹起直到你松 ...
- Debounce 和 Throttle【转载】
在处理诸如 resize.scroll.mousemove 和 keydown/keyup/keypress 等事件的时候,通常我们不希望这些事件太过频繁地触发,尤其是监听程序中涉及到大量的计算或者有 ...
- 白话debounce和throttle
遇到的问题 在开发过程中会遇到频率很高的事件或者连续的事件,如果不进行性能的优化,就可能会出现页面卡顿的现象,比如: 鼠标事件:mousemove(拖曳)/mouseover(划过)/mouseWhe ...
- 老李推荐:第6章7节《MonkeyRunner源码剖析》Monkey原理分析-事件源-事件源概览-注入按键事件实例
老李推荐:第6章7节<MonkeyRunner源码剖析>Monkey原理分析-事件源-事件源概览-注入按键事件实例 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜 ...
- 函数防抖与函数节流 封装好的debounce和throttle函数
/** * 空闲控制 返回函数连续调用时,空闲时间必须大于或等于 wait,func 才会执行 * * @param {function} func 传入函数,最后一个参数是额外增加的this对象,. ...
- debounce与throttle区别
在2011年,Twitter网站曾爆出一个问题:在主页往下滚动时,页面会变得缓慢以致没有响应.John Resig发表了一篇文章< a blog post about the problem&g ...
- underscore里面的debounce与throttle
throttle 策略的电梯.保证如果电梯第一个人进来后,15秒后准时运送一次,不等待.如果没有人,则待机. debounce 策略的电梯.如果电梯里有人进来,等待15秒.如果又人进来,15秒等待重新 ...
- debounce、throttle、requestAnimationFrame
今天review同事代码,代码实现了返回顶部的功能,用到了lodash库中的throttle,我看着眼生,于是乎去看了下lodash文档,然后牵出了debounce,具体的知识点,这里不再赘述,底部的 ...
- debounce还是throttle(去抖和节流)
debounce 去抖 我的理解很简单,比方说window.onscroll会疯狂触发handler,此时给它一个debounce(handler, delayTime). 就是不管你延时时间内触发了 ...
随机推荐
- Loadrunner下WebTours系统自带的用户名和密码
打开:http://127.0.0.1:1080/WebTours/ 系统默认自带两个用户名和密码,位于~\WebTours\MercuryWebTours\users: 1.用户名:joe,密码:y ...
- nio笔记
http://blog.csdn.net/z69183787/article/category/2191483此人的博客 首先你要知道阻塞和非阻塞的概念,阻塞体现在这个线程不能干别的了,只能在这里等着 ...
- csu 1592(区间DP)
1592: 石子归并 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 356 Solved: 148[Submit][Status][Web Board ...
- [目标检测]RCNN系列原理
1 RCNN 1.1 训练过程 (1) 训练时采用fine-tune方式: 先用Imagenet(1000类)训练,再用PASCAL VOC(21)类来fine-tune.使用这种方式训练能够提高8个 ...
- Adminimize 插件:WordPress根据用户角色显示/隐藏某些后台功能
倡萌刚才分享了 WordPress根据用户角色隐藏文章/页面的功能模块(Meta Boxes),如果你还想根据不同用户角色显示或隐藏后台的某些功能,比如 顶部工具条.左边导航菜单.小工具.仪表盘.菜单 ...
- day3 作业
文件操作用户很广泛,我们经常对文件进行操作: global log 127.0.0.1 local2 daemon maxconn log 127.0.0.1 local2 info defaults ...
- Dockerfile 备份
dotnet core app FROM microsoft/dotnet:1.1.0-runtime WORKDIR /mvcApp COPY ./out . ENTRYPOINT ["d ...
- char *s 和char s[]的区别
char *s 和 char s[] 的区别小结 博客分类: C语言 c教育 . 最近的项目中有不少c的程序,在与项目新成员的交流中发现,普遍对于char *s1 和 char s2[] 认识有误区( ...
- Socket 编程(二)
首先,看主界面 点击链接按钮,开始建立与服务端的连接 Socket socket = null; private void btnStart_Click(object sender, EventArg ...
- 微信开发(一)SAE环境搭建
登录新浪sae平台,点击sae 点击创建新应用->继续创建 环境选择: 填好后点击创建应用 点击创建版本 点击链接可以访问,点击编辑代码可以在线编辑,代码上传可以是svn,git,可以在线上传 ...