throttle和debounce
遇到的问题
在开发过程中会遇到频率很高的事件或者连续的事件,如果不进行性能的优化,就可能会出现页面卡顿的现象,比如:
- 鼠标事件:mousemove(拖曳)/mouseover(划过)/mouseWheel(滚屏)
 - 键盘事件:keypress(基于ajax的用户名唯一性校验)/keyup(文本输入检验、自动完成)/keydown(游戏中的射击)
 - window的resize/scroll事件(DOM元素动态定位)
 
为了解决这类问题,常常使用的方法就是throttle(节流)和debounce(去抖)。throttle(节流)和debounce(去抖)都是用来控制某个函数在一定时间内执行多少次的解决方案,两者相似而又不同。
下面就具体的看看两者的相似和区别。
认识throttle和debounce
throttle和debounce的作用就是确认事件执行的方式和时机,以前总是不太清楚两者的区别,容易把二者弄混。
下面就通过两个简单的场景描述一下debounce和throttle,以后想到这两个场景就不会再弄混了:
debounce假设你正在乘电梯上楼,当电梯门关闭之前发现有人也要乘电梯,礼貌起见,你会按下开门开关,然后等他进电梯; 如果在电梯门关闭之前,又有人来了,你会继续开门;这样一直进行下去,你可能需要等待几分钟,最终没人进电梯了,才会关闭电梯门,然后上楼。
所以debounce的作用是,当调用动作触发一段时间后,才会执行该动作,若在这段时间间隔内又调用此动作则将重新计算时间间隔。
throttle假设你正在乘电梯上楼,当电梯门关闭之前发现有人也要乘电梯,礼貌起见,你会按下开门开关,然后等他进电梯;  但是,你是个没耐心的人,你最多只会等待电梯停留一分钟;在这一分钟内,你会开门让别人进来,但是过了一分钟之后,你就会关门,让电梯上楼。
所以throttle的作用是,预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新的时间周期。
简单实现
有了上面的了解,就可以去实现简单debounce和throttle了。
debounce实现
首先来看看debounce的实现,根据前面对debounce的描述:
- debounce函数会通过闭包维护一个timer
 - 当同一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
 
作者:Larissa_
链接:https://www.jianshu.com/p/e8ad62e29b03
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
throttle和debounce的更多相关文章
- [概念] js的函数节流和throttle和debounce详解
		
js的函数节流和throttle和debounce详解:同样是实现了一个功能,可能有的效率高,有的效率低,这种现象在高耗能的执行过程中区分就比较明显.本章节一个比较常用的提高性能的方式,通常叫做&qu ...
 - javascript中的throttle和debounce
		
throttle 我们这里说的throttle就是函数节流的意思.再说的通俗一点就是函数调用的频度控制器,是连续执行时间间隔控制.主要应用的场景比如: 1.鼠标移动,mousemove 事件2.DOM ...
 - 【 js 性能优化】throttle 与 debounce 节流
		
在看 underscore.js 源码的时候,接触到了这样两个方法,很有意思: 我先把实现的代码撂在下面,看不懂的可以先跳过,但是跳过可不是永远跳过哦- 一个是 throttle: _.throttl ...
 - 试议常用Javascript 类库中 throttle 与 debounce 辅助函数的区别
		
问题的引出 看过我前面两篇博客的童鞋可能会注意到都谈到了事件处理的优化问题. 在很多应用中,我们需要控制函数执行的频率, 例如 窗口的 resize,窗口的 scroll 等操作,事件触发的频率非常高 ...
 - 【 js 性能优化】【源码学习】underscore throttle 与 debounce 节流
		
在看 underscore.js 源码的时候,接触到了这样两个方法,很有意思: 我先把实现的代码撂在下面,看不懂的可以先跳过,但是跳过可不是永远跳过哦- 一个是 throttle: _.throttl ...
 - 日常的例子说明 throttle 和 debounce 的区别
		
不小心接触到 throttle 和 debounce,按捺不住猎奇的心理,找这两个函数的资料. 然而百度到的各种对他们的理解,我去啊. 艰难地搞明白他们是干嘛的之后,忍不住举个例子说说自己的理解,希望 ...
 - [JavaScript] 节流(throttle)-防抖(debounce) 不懵圈指北
		
网易云课堂 > 微专业 > 前端高级开发工程师 01.前端高级-JavaScript进阶 > 3.函数式编程 Underscore源码分析 > 3.4.3 throttle 与 ...
 - throttle和debounce简单实现
		
function debounce(delay,fn){ var timer; return function(){ var ctx = this,args = arguments; clearTim ...
 - 精简的javascript下throttle和debounce代码
		
//频率控制 函数连续调用时,fn 执行频率限定为 1次/waitMs.立即执行1次 function throttle(fn, waitMs) { var lastRun = 0; return f ...
 
随机推荐
- pytorch中tensor张量的创建
			
import torch import numpy as np print(torch.tensor([1,2,3])) print(torch.tensor(np.arange(15).reshap ...
 - 高质量动漫实时画质增强器Anime4K在mpv上的配置
			
Anime4K地址 https://github.com/bloc97/Anime4K mpv地址 https://mpv.io/ 这个要错峰下载,网速不太好 在C盘用户\..\AppData\ ...
 - 使用 Junit + Mockito 实践单元测试
			
一.前言 相信做过开发的同学,都多多少少写过下面的代码,很长一段时间我一直以为这就是单元测试... @SpringBootTest @RunWith(SpringRunner.class) publi ...
 - PHP生成桌面快捷方式,保存一个网页至桌面上成为快捷方式
			
header("Content-Type: application/octet-stream; charset=utf8"); header("Content-Dispo ...
 - Linux C语言 检测文件是否存在
			
头文件 unistd.h ) { // file exists } else { // file doesn't exist } You can also use R_OK, W_OK, and X_ ...
 - 微服务为什么一定要用docker
			
引言 早在2013年的时候,docker就已经发行,然而那会还是很少人了解docker.一直到2014年,Martin Fowler提出了微服务的概念,两个不相干的技术终于走在了一起,创造了今天的辉煌 ...
 - mybatis if test标签的使用
			
2019独角兽企业重金招聘Python工程师标准>>> 在使用mybatis 有时候需要进行判断的. 而我们知道mybatis获取值有两种方式 #{}和${}的. 那么,在mybat ...
 - python selenium(常用关键字)
			
1.文本按钮操作相关: send_keys()输入文本 from selenium import webdriver import time dr = webdriver.Chrome() dr.ge ...
 - 编写简单的内核模块及内核源码下载,内核模块Makefile编写
			
CentOS的内核源码默认是没有下载的,需要自己下载,首先安装linux的时候就应该知道linux的版本,我装的是Centos7的 下面查一下内核的版本,使用下面的命令 [scut_lcw@local ...
 - Nginx读书笔记三----资源分配
			
1.内存及磁盘资源分配 1.1 在磁盘中存储HTTP请求体 语法: client_body_in_file_only on|clean|off; 默认: client_body_in_file_onl ...