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 相关文章推荐
从Ajax到JQuery Ajax学习
Feb 14 Javascript
ExtJs3.0中Store添加 baseParams 的Bug
Mar 10 Javascript
原生JavaScript实现连连看游戏(附源码)
Nov 05 Javascript
JavaScript闭包函数访问外部变量的方法
Aug 27 Javascript
IE下支持文本框和密码框placeholder效果的JQuery插件分享
Jan 31 Javascript
JS三级可折叠菜单实现方法
Feb 29 Javascript
深入理解Javascript中的自执行匿名函数
Jun 03 Javascript
Node.js与Sails redis组件的使用教程
Feb 14 Javascript
干货!教大家如何选择Vue和React
Mar 13 Javascript
详解vue-cli 脚手架项目-package.json
Jul 04 Javascript
vue axios请求频繁时取消上一次请求的方法
Nov 10 Javascript
在vue中封装的弹窗组件使用队列模式实现方法
Jul 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
收听困难?教您超简便短波广播抗干扰方法!
2021/03/01 无线电
PHP开发过程中常用函数收藏
2009/12/14 PHP
php实现的支持imagemagick及gd库两种处理的缩略图生成类
2014/09/23 PHP
php计算整个mysql数据库大小的方法
2015/06/19 PHP
PHP编程开发怎么提高编程效率 提高PHP编程技术
2015/11/09 PHP
PHP四种排序算法实现及效率分析【冒泡排序,插入排序,选择排序和快速排序】
2018/04/27 PHP
PHP 图片合成、仿微信群头像的方法示例
2019/10/25 PHP
JavaScript高级程序设计 XML、Ajax 学习笔记
2011/09/10 Javascript
js使下拉列表框可编辑不止是选择
2013/12/12 Javascript
js 绑定键盘鼠标事件示例代码
2014/02/12 Javascript
js文件Cookie存取值示例代码
2014/02/20 Javascript
JS实现双击编辑可修改状态的方法
2015/08/14 Javascript
JS实现兼容性好,带缓冲的动感网页右键菜单效果
2015/09/18 Javascript
推荐10 个很棒的 jQuery 特效代码
2015/10/04 Javascript
JS实现的竖向折叠菜单代码
2015/10/21 Javascript
JS实现复制内容到剪贴板功能兼容所有浏览器(推荐)
2016/06/17 Javascript
js中用cssText设置css样式的简单方法
2016/09/19 Javascript
js实现背景图自适应窗口大小
2017/01/10 Javascript
vue实现的下拉框功能示例
2019/01/29 Javascript
js闭包和垃圾回收机制示例详解
2021/03/01 Javascript
python根据经纬度计算距离示例
2014/02/16 Python
python3写爬取B站视频弹幕功能
2017/12/22 Python
python爬虫获取多页天涯帖子
2018/02/23 Python
实例讲解python中的序列化知识点
2018/10/08 Python
pygame游戏之旅 如何制作游戏障碍
2018/11/20 Python
python腾讯语音合成实现过程解析
2019/08/01 Python
python 普通克里金(Kriging)法的实现
2019/12/19 Python
伦敦最有品味的百货:Liberty London
2016/11/12 全球购物
软件测试笔试题
2012/10/25 面试题
给妈妈洗脚活动方案
2014/08/16 职场文书
土木工程专业本科生求职信
2014/10/01 职场文书
2014年工会工作总结
2014/11/12 职场文书
2014年仓库管理员工作总结
2014/11/18 职场文书
2014年民政工作总结
2014/11/26 职场文书
女性健康知识讲座主持词
2015/07/04 职场文书
面试中老生常谈的MySQL问答集锦夯实基础
2022/03/13 MySQL