JavaScript中定时控制Throttle、Debounce和Immediate详解


Posted in Javascript onNovember 17, 2016

前言

我们称这些行为events(事件),和响应callbacks(回调)。连续的事件流被称为event stream(事件流)。这些行为发生的速度不是我们能手动控制的。但是我们可以控制何时和如何激活正确的响应。有一些技术为我们提供精确的控制。

Throttle

在现代浏览器中,帧速率为60fps是流畅性能的目标,给定我们16.7ms的时间预算用于响应一些事件所有需要的更新。这样可以推断,如果每秒发生n个事件并且回调执行,需要t秒的时间,为了流畅运行,

1 / n >= t

如果t以毫秒为单位,

1000 / n >= t

如果你曾经使用mousemove事件,你会知道产生mousemove事件的数量每秒可以超过60次。如果我们的回调需要超过16.7ms,那就开始凌乱了。

var then = 0;
 
function log() {
 var now = Date.now();
 if (1000 / (now - then) > 60) {
  console.log('It\'s over 9000!!!');
 }
 then = now;
}
 
window.onmousemove = log;

实现

Throttle 允许我们限制我们激活响应的数量。我们可以限制每秒回调的数量。反过来,也就是说在激活下一个回调之前要等待多少时间;

var delta = 1000;
var then = 0;
 
function log() {
 console.log('foo');
}
 
function throttledLog() {
 var now = Date.now();
 if (now - then >= delta) {
  log();
 
  then = now;
 }
};
 
window.onmousemove = throttledLog;

我们可以用 fps替换delta,并推断出不同的代码。

var fps = 60;
...
function throttledLog() {
 var now = Date.now();
 if (1000 / (now - then) < = fps) {
  log();
 
  then = now;
 }
};
 
window.onmousemove = throttledLog;

我们也可以通过使用setTimeout来实现相同的结果。 但是,不是检查时间差,而是检查状态变化。

第一次,我们可以安全地激活回调。一旦完成,只有在等待 delta 时间之后才能再次激活回调。

var delta = 1000;
var safe = true;
 
function log() {
 console.log('foo');
}
 
function throttledLog() {
 if (safe) {
  log();
 
  safe = false;
  setTimeout(function() {
   safe = true;
  }, delta);
 }
};
 
window.onmousemove = throttledLog;

Debounce

这个术语-去抖动 来自电子学的领域,手动开关输入的信号被发送到数字电路中。在电子学中,当你按一个物理按钮一次,数字电路可能读到多个按压,因为按钮的物理属性(金属触点,弹簧,磨损件等)。

去抖动意味着采集到的所有这些波动的信号,并把它们当作一个。

例子

一个简单的例子已经存在于JS中:keydown vs keyup。假设您正在处理一个项目,并且需要输入内容。但是你想要每次敲击键盘得到一个字符。输入时,如果长按一个键,keydown事件将连续被触发,但是 keyup 事件只有在按键被释放时才会触发。

window.onkeyup = function() {
 console.log('onkeyup');
}
 
window.onkeydown = function() {
 console.log('onkeydown');
}

这种行为上的差异对于确定输入是否已完成是有用的。在示例场景中,它是你将使用的keyup事件。在某种程度上,我们可以说keydown 是原始输入,keyup 是去抖动输入。

实现

当事件发生时,我们不会立即激活回调。相反,我们等待一定的时间并检查相同的事件是否再次触发。如果是,我们重置定时器,并再次等待。如果在等待期间没有发生相同的事件,我们就立即激活回调。

var delta = 1000;
var timeoutID = null;
 
function log() {
 console.log('foo');
}
 
function debouncedLog() {
 clearTimeout(timeoutID); // reset timer
 timeoutID = setTimeout(function() {
  // wait for some time
  // and check if event happens again
  log();
 }, delta);
};
 
window.onkeydown = debouncedLog;

Immediate

Immediate是Debounce的精确版本。比起 Debounce 的 等待后续事件触发,然后再激活回调,Immediate 是 立即激活回调,然后等待后续事件在一定时间内触发。

实现

就像Throttle的情况一样,我们需要一个状态变量来检查是否应该激活我们的回调。我们在Debounce不需要一个,因为timeoutID隐式管理这部分。

var delta = 1000;
var timeoutID = null;
var safe = true;
 
function log() {
 console.log('foo');
}
 
function immediatedLog() {
 if (safe) {
  log();
  safe = false;
 }
 
 clearTimeout(timeoutID);
 timeoutID = setTimeout(function() {
  safe = true;
 }, delta);
};
 
window.onkeydown = immediatedLog;

总结

以上就是这篇文章的全部内容了,在这篇文章中,我们已经探索了用作定时函数的最常见的技术。希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

Javascript 相关文章推荐
Prototype 学习 工具函数学习($w,$F方法)
Jul 12 Javascript
js实现倒计时时钟的示例代码
Dec 17 Javascript
jQuery对象的length属性用法实例
Dec 27 Javascript
javascript实用方法总结
Feb 06 Javascript
JS实现兼容各浏览器解析XML文档数据的方法
Jun 01 Javascript
jquery实现页面虚拟键盘特效
Aug 08 Javascript
jQuery实现的多滑动门,多选项卡效果代码
Mar 28 Javascript
详解vue 项目白屏解决方案
Oct 31 Javascript
JavaScript数据结构与算法之检索算法实例分析【顺序查找、最大最小值、自组织查询】
Feb 22 Javascript
vue.js的简单自动求和计算实例
Nov 08 Javascript
layui实现显示数据表格、搜索和修改功能示例
Jun 03 Javascript
vue cli3.0打包上线静态资源找不到路径的解决操作
Aug 03 Javascript
JS动态的把左边列表添加到右边的实现代码(可上下移动)
Nov 17 #Javascript
leaflet的开发入门教程
Nov 17 #Javascript
JavaScript中关于iframe滚动条的去除和保留
Nov 17 #Javascript
JS实现倒计时(天数、时、分、秒)
Nov 16 #Javascript
探讨AngularJs中ui.route的简单应用
Nov 16 #Javascript
jQuery 插件封装的方法
Nov 16 #Javascript
Node.js 数据加密传输浅析
Nov 16 #Javascript
You might like
关于php fread()使用技巧
2010/01/22 PHP
Laravel框架中集成MongoDB和使用详解
2019/10/17 PHP
javascript flash下fromCharCode和charCodeAt方法使用说明
2008/01/12 Javascript
javascript字符串函数汇总
2015/12/06 Javascript
如何解决easyui自定义标签 datagrid edit combobox 手动输入保存不上
2015/12/26 Javascript
JavaScript学习小结之使用canvas画“哆啦A梦”时钟
2016/07/24 Javascript
微信小程序 详解页面跳转与返回并回传数据
2017/02/13 Javascript
学习使用Bootstrap输入框、导航、分页等常用组件
2017/05/11 Javascript
使用 Node.js 对文本内容分词和关键词抽取
2017/05/27 Javascript
谈谈VUE种methods watch和compute的区别和联系
2017/08/01 Javascript
js replace 全局替换的操作方法
2018/06/12 Javascript
Layui数据表格之获取表格中所有的数据方法
2018/08/20 Javascript
vue+vue-router转场动画的实例代码
2018/09/01 Javascript
vue 使用element-ui中的Notification自定义按钮并实现关闭功能及如何处理多个通知
2019/08/17 Javascript
uni app仿微信顶部导航条功能
2019/09/17 Javascript
[03:07]【DOTA2亚洲邀请赛】我们,梦开始的地方
2017/03/07 DOTA
python中getattr函数使用方法 getattr实现工厂模式
2014/01/20 Python
python持久性管理pickle模块详细介绍
2015/02/18 Python
利用Python为iOS10生成图标和截屏
2016/09/24 Python
Python实现动态图解析、合成与倒放
2018/01/18 Python
tensorflow实现图像的裁剪和填充方法
2018/07/27 Python
Django组件cookie与session的具体使用
2019/06/05 Python
解决pyinstaller 打包exe文件太大,用pipenv 缩小exe的问题
2020/07/13 Python
Linux系统下升级pip的完整步骤
2021/01/31 Python
如何利用CSS3制作3D效果文字具体实现样式
2013/05/02 HTML / CSS
详解CSS3中@media的实际使用
2015/08/04 HTML / CSS
css3通过scale()、rotate()实现放大、旋转
2020/03/19 HTML / CSS
美国最大的家庭鞋类零售商之一:Shoe Carnival
2017/10/06 全球购物
ProForm英国站点:健身房和健身器材网上商店
2019/06/05 全球购物
ECOSUSI官网:女式皮革背包
2019/09/27 全球购物
俄罗斯达美乐比萨外送服务:Domino’s Pizza
2020/12/18 全球购物
电厂厂长岗位职责
2014/01/02 职场文书
技术岗位竞聘演讲稿
2014/05/16 职场文书
cf战队收人口号
2014/06/21 职场文书
评测 | 大屏显示带收音机的高端音箱,JBL TUNE2便携式插卡音箱实测
2021/04/24 无线电
js 实现Material UI点击涟漪效果示例
2022/09/23 Javascript