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 相关文章推荐
js 提交和设置表单的值
Dec 19 Javascript
父子窗体间传递JSON格式的数据的代码
Dec 25 Javascript
js父窗口关闭时子窗口随之关闭完美解决方案
Apr 29 Javascript
jQuery实现为图片添加镜头放大效果的方法
Jun 25 Javascript
JS实现slide文字框缩放伸展效果代码
Nov 05 Javascript
Boostrap入门准备之border box
May 09 Javascript
plupload+artdialog实现多平台上传文件
Jul 19 Javascript
微信小程序 Audio API详解及实例代码
Sep 30 Javascript
通过npm引用的vue组件使用详解
Mar 02 Javascript
jQuery给表格添加分页效果
Mar 02 Javascript
详解Angular4中路由Router类的跳转navigate
Jun 09 Javascript
Bootstrap 3多级下拉菜单实例
Nov 23 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导入导出CSV文件
2014/11/03 PHP
PHP实现获取域名的方法小结
2014/11/05 PHP
PHP中应该避免使用同名变量(拆分临时变量)
2015/04/03 PHP
PHP实现mysqli批量执行多条语句的方法示例
2017/07/22 PHP
php5对象复制、clone、浅复制与深复制实例详解
2019/08/14 PHP
Laravel框架中集成MongoDB和使用详解
2019/10/17 PHP
使用Git实现Laravel项目的自动化部署
2019/11/24 PHP
php下的原生ajax请求用法实例分析
2020/02/28 PHP
Ucren Virtual Desktop V2.0
2006/11/07 Javascript
BootStrap 轮播插件(carousel)支持左右手势滑动的方法(三种)
2016/07/07 Javascript
bootstrap配合Masonry插件实现瀑布式布局
2017/01/18 Javascript
微信小程序基于slider组件动态修改标签透明度的方法示例
2017/12/04 Javascript
JS实现简单的浮动碰撞效果示例
2017/12/28 Javascript
vue3.0 CLI - 2.1 -  component 组件入门教程
2018/09/14 Javascript
Windows下Node爬虫神器Puppeteer安装记
2019/01/09 Javascript
详解ES6 export default 和 import语句中的解构赋值
2019/05/28 Javascript
Python ORM框架SQLAlchemy学习笔记之数据添加和事务回滚介绍
2014/06/10 Python
一步步解析Python斗牛游戏的概率
2016/02/12 Python
Python语言实现百度语音识别API的使用实例
2017/12/13 Python
Python图像的增强处理操作示例【基于ImageEnhance类】
2019/01/03 Python
html5嵌入内容_动力节点Java学院整理
2017/07/07 HTML / CSS
Html5之title吸顶功能
2018/06/04 HTML / CSS
P D PAOLA法国官网:西班牙著名的珠宝首饰品牌
2020/02/15 全球购物
医学类导师推荐信范文
2013/11/19 职场文书
食品安全检查制度
2014/02/03 职场文书
单位工程竣工验收方案
2014/03/16 职场文书
中央空调节能方案
2014/06/15 职场文书
教育项目合作协议书格式
2014/10/17 职场文书
2014年高中班主任工作总结
2014/11/08 职场文书
体育教师个人总结
2015/02/09 职场文书
创业项目大全(适合在家创业的项目)
2019/08/15 职场文书
假如给我三天光明:舟逆水而行,人遇挫而达 
2019/10/29 职场文书
Python基础之数据类型知识汇总
2021/05/18 Python
解决MySQL Varchar 类型尾部空格的问题
2022/04/06 MySQL
浅谈音视频 pts dts基本概念及理解
2022/08/05 数码科技
Win10开机修复磁盘错误怎么跳过?Win10关闭开机磁盘检查的方法
2022/09/23 数码科技