遇到的问题

在开发过程中会遇到频率很高的事件或者连续的事件,如果不进行性能的优化,就可能会出现页面卡顿的现象,比如:

  1. 鼠标事件:mousemove(拖曳)/mouseover(划过)/mouseWheel(滚屏)
  2. 键盘事件:keypress(基于ajax的用户名唯一性校验)/keyup(文本输入检验、自动完成)/keydown(游戏中的射击)
  3. window的resize/scroll事件(DOM元素动态定位)

为了解决这类问题,常常使用的方法就是throttle(节流)debounce(去抖)。throttle(节流)和debounce(去抖)都是用来控制某个函数在一定时间内执行多少次的解决方案,两者相似而又不同。

下面就具体的看看两者的相似和区别。

认识throttle和debounce

throttle和debounce的作用就是确认事件执行的方式和时机,以前总是不太清楚两者的区别,容易把二者弄混。

下面就通过两个简单的场景描述一下debounce和throttle,以后想到这两个场景就不会再弄混了:

debounce
假设你正在乘电梯上楼,当电梯门关闭之前发现有人也要乘电梯,礼貌起见,你会按下开门开关,然后等他进电梯;
如果在电梯门关闭之前,又有人来了,你会继续开门;
这样一直进行下去,你可能需要等待几分钟,最终没人进电梯了,才会关闭电梯门,然后上楼。

所以debounce的作用是,**当调用动作触发一段时间后,才会执行该动作,若在这段时间间隔内又调用此动作则将重新计算时间间隔**。

throttle
假设你正在乘电梯上楼,当电梯门关闭之前发现有人也要乘电梯,礼貌起见,你会按下开门开关,然后等他进电梯;
但是,你是个没耐心的人,你最多只会等待电梯停留一分钟;
在这一分钟内,你会开门让别人进来,但是过了一分钟之后,你就会关门,让电梯上楼。

所以throttle的作用是,**预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新的时间周期**。

简单实现

有了上面的了解,就可以去实现简单debounce和throttle了。

debounce实现

首先来看看debounce的实现,根据前面对debounce的描述:

  1. debounce函数会通过闭包维护一个timer
  2. 当同一action在delay的时间间隔内再次触发,则清理timer,然后重新设置timer

可以在Chrome中运行下面的代码,看看debounce的效果,代码Github链接

var debounce = function(action, delay) {
var timer = null; return function() {
var self = this,
args = arguments; clearTimeout(timer);
timer = setTimeout(function() {
action.apply(self, args)
}, delay);
}
} // example
function resizeHandler() {
console.log("resize");
} window.onresize = debounce(resizeHandler, 300);

throttle实现

throttle跟debounce的最大不同就是,throttle会有一个阀值,当到达阀值的时候action必定会执行一次。

所以throttle的实现可以基于前面的debounce的实现,只需要加上一个阀值,代码Github链接

var throttleV1 = function(action, delay, mustRunDelay) {
var timer = null,
startTime; return function() {
var self = this,
args = arguments,
currTime = new Date(); clearTimeout(timer); if(!startTime) {
startTime = currTime;
} if(currTime - startTime >= mustRunDelay) {
action.apply(self, args);
startTime = currTime;
}
else {
timer = setTimeout(function() {
action.apply(self, args);
}, delay);
}
};
};

其实,对于上面的实现可以进心简化,只是通过闭包维护一个开始的时间:

var throttleV2 = function(action, delay){
var statTime = 0; return function() {
var currTime = +new Date(); if (currTime - statTime > delay) {
action.apply(this, arguments);
statTime = currTime ;
}
}
} // example
function resizeHandler() {
console.log("resize");
} window.onresize = throttleV2(resizeHandler, 300);

总结

通过前面的介绍,应该对debounce和throttle有一个直观的认识了:

  • debounce:把触发非常频繁的事件合并成一次执行
  • throttle:设置一个阀值,在阀值内,把触发的事件合并成一次执行;当到达阀值,必定执行一次事件

了解了throttle和debounce之后,下面看看他们的常用场景:

debounce

  • 对于键盘事件,当用户输入比较频繁的时候,可以通过debounce合并键盘事件处理
  • 对于ajax请求的情况,例如当页面下拉超过一定返回就通过ajax请求新的页面内容,这时候可以通过debounce合并ajax请求事件

throttle

  • 对于键盘事件,当用户输入非常频繁,但是我们又必须要在一定时间内(阀值)内执行处理函数的时候,就可以使用throttle

    • 例如,一些网页游戏的键盘事件
  • 对于鼠标移动和窗口滚动,鼠标的移动和窗口的滚动会带来大量的事件,但是在一段时间内又必须看到页面的效果

    • 例如对于可以拖动的div,如果使用debounce,那么div会在拖动停止后一下子跳到目标位置;这时就需要使用throttle

白话debounce和throttle的更多相关文章

  1. Debounce 和 Throttle 的原理及实现---防止频繁触发某事件

    原文:http://blog.csdn.net/redtopic/article/details/69396722 在处理诸如 resize.scroll.mousemove 和 keydown/ke ...

  2. debounce 与 throttle 区别

    原文地址:http://undefinedblog.com/debounce-and-throttle/ 二.什么是debounce    1. 定义 如果用手指一直按住一个弹簧,它将不会弹起直到你松 ...

  3. 函数防抖与函数节流 封装好的debounce和throttle函数

    /** * 空闲控制 返回函数连续调用时,空闲时间必须大于或等于 wait,func 才会执行 * * @param {function} func 传入函数,最后一个参数是额外增加的this对象,. ...

  4. debounce与throttle区别

    在2011年,Twitter网站曾爆出一个问题:在主页往下滚动时,页面会变得缓慢以致没有响应.John Resig发表了一篇文章< a blog post about the problem&g ...

  5. underscore里面的debounce与throttle

    throttle 策略的电梯.保证如果电梯第一个人进来后,15秒后准时运送一次,不等待.如果没有人,则待机. debounce 策略的电梯.如果电梯里有人进来,等待15秒.如果又人进来,15秒等待重新 ...

  6. debounce、throttle、requestAnimationFrame

    今天review同事代码,代码实现了返回顶部的功能,用到了lodash库中的throttle,我看着眼生,于是乎去看了下lodash文档,然后牵出了debounce,具体的知识点,这里不再赘述,底部的 ...

  7. debounce还是throttle(去抖和节流)

    debounce 去抖 我的理解很简单,比方说window.onscroll会疯狂触发handler,此时给它一个debounce(handler, delayTime). 就是不管你延时时间内触发了 ...

  8. Debounce 和 Throttle【转载】

    在处理诸如 resize.scroll.mousemove 和 keydown/keyup/keypress 等事件的时候,通常我们不希望这些事件太过频繁地触发,尤其是监听程序中涉及到大量的计算或者有 ...

  9. JS魔法堂:函数节流(throttle)与函数去抖(debounce)

    一.前言 以下场景往往由于事件频繁被触发,因而频繁执行DOM操作.资源加载等重行为,导致UI停顿甚至浏览器崩溃. 1. window对象的resize.scroll事件 2. 拖拽时的mousemov ...

随机推荐

  1. asp.net mvc4 使用 System.Web.Optimization 对javascript和style的引入、代码合并和压缩的优化(ScriptBundle,StyleBundle,Bundling and Minification )

    Bundling and Minification两个单词对今天的内容有个比较好的总结. 问题所在 一. 在asp.net包括mvc项目中,引入js和css也许有人认为是个很容易和很简单操作的事情,v ...

  2. Electron - 创建跨平台的桌面客户的应用程序

    Electron 框架的前身是 Atom Shell,可以让你写使用 JavaScript,HTML 和 CSS 构建跨平台的桌面应用程序.它是基于io.js 和 Chromium 开源项目,并用于在 ...

  3. js判断radiobuttonlist的选中值显示/隐藏其它模块

    <script> $(function () { var SelectVal = $("input[name='rblGJS']:checked").val(); if ...

  4. 移动web开发介绍——浏览器

    前段时间了解学习了一下<移动Web手册>,觉得真的需要这种不是偏向技术.框架或工具的书籍,只是单纯的讲解一些关于移动Web最基本的知识.正好今天整理一部分之前学习过的内容,记录和分享,也方 ...

  5. Flex Viewer (二)——体系结构

    一.概述 在上一篇文章<深入浅出Flex Viewer (一)——概述>中,笔者对Flex Viewer用于构建以地图为中心的富客户端(RIA)应用的原型的功能和价值做了简要地介绍.在本文 ...

  6. linux 压缩命令详解

    原文地址:http://www.2cto.com/os/201112/114982.html 编写shell脚本的时候经常需要解压缩到指定的文件夹,tar命令是最常用的 参考一下说明,其中注意-C的用 ...

  7. 用typedef自定义类型语法你真的会吗

    关于typedef  我们学习typedef的时候,他的定义语法是:typedef+类型+别名,但是按照上面的格式,自定义数组怎么定义呢,是这样tepedef int a[10] 别名?还是这样tep ...

  8. Ida动态修改android程序的内存数据和寄存器数值,绕过so文件的判断语句

    我们继续分析自毁程序密码这个app,我们发现该程序会用fopen ()打开/proc/[pid]/status这个文件,随后会用fgets()和strstr()来获取,于是我们在strstr()处下个 ...

  9. 你真的了解UIScrollView吗?

    一:首先查看一下关于UIScrollView的定义 NS_CLASS_AVAILABLE_IOS(2_0) @interface UIScrollView : UIView <NSCoding& ...

  10. 【代码笔记】iOS-手机号验证

    代码: - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. // ...