【Why】用来记录我对抖动和节流的学习路径。学习目的:想了解去抖动和节流的基本概念以及如何实现,网上的资源已经很多了,所以我会以贴链接为主,加一点自己的思考和理解。
【How】如何找到相关文章进行学习:方法一:百度谷歌,我第一次接触抖动和节流这两个名词,百度谷歌到的帖子比较难理解,所以找了第二个方法。方向二:去一些已经把前端资料整理好了的github上找想要的帖子。这里推荐一个github链接:https://github.com/qianguyihao/Web,这个博主收集了比较完整的前端资料,我是在那里找到对应的“去抖动和节流”的文章:详细链接
下面就是贴链接,贴代码的时间啦!
实例解析防抖动(Debouncing)和节流阀(Throttling)以及这篇文章内包含的两个链接要看:
这三篇文章里的代码全为js,直接用F12的console窗口就能看效果,非常直观!对初学者及其友好
其他文章:JS函数防抖和函数节流、JavaScript函数节流和函数防抖之间的区别
Lodash 的 _.debounce
和 _.throttle:
一句话说清楚_.throttle和_.debounce的区别
【自己的笔记】
来自:JavaScript中的定时控制-Throttle、Debounce、Immediate的基本概念
Throttle(节流)
在现代浏览器中,帧速率为60fps是流畅性能的目标(大于60fps可以但没必要,但小于60fps就会出现卡顿),给定我们16.7ms(1s刷新60张图片,1张图片需要16.7ms。如果1张图需要的时间大于16.7ms就会开始出现卡顿)的时间预算用于响应一些事件所有需要的更新。这样可以推断,如果每秒发生
n
个事件并且回调执行(是n个事件都是属于回调函数,还是n个事件都有回调函数?),需要t
秒的时间(谁需要t秒?回调的函数吗?还是加上一共要 t 秒?还是每个事件需要 t 秒?),为了流畅运行,1 / n >= t(1 / n是一个事件需要的时间,t是什么东西?为什么是大于等于?)
如果
t
以毫秒为单位,1000 / n >= t
如果你曾经使用mousemove事件,你会知道产生
mousemove
事件的数量每秒可以超过60次。如果我们的回调需要超过16.7ms,那就开始凌乱了。(什么叫开始凌乱?尝试解答:60fps代表了60张图平均每张图用16.67ms,即60*16.67ms=1s,如果图片超过60张,对应的,要把每张图的时间缩小。否则会出现卡顿。而开始凌乱的意思就是会出现卡顿)
接下来就举了一个js的例子来说明凌乱:
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;
但是,now-then要小于16.67ms才会输出“It\'s over 9000!!!”,小于16.67ms就代表不会卡顿啊。这样的话,凌乱指的就不说卡顿了,那凌乱指什么凌乱了?
我想的是,mousemove太灵敏了,一有鼠标的移动,就会输出。但是不能从dom上控制mouseover,所以只能从输出函数log入手,比如设置等待多少秒才调用log之类的。就有了(还是这个文章)下面的throttledLog(),这个函数实现的是控制调用log的时间,当满足设定的等待时间时,才能调用log。两个方法:①if判断(检查时间差) ②setTimeout(检查状态变化)
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;
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;
补充:节流就是为了让用户的方法在某个时间段内只执行一次,我们需要保存上次执行的时间点与定时器。参考链接
函数节流会用在比input, keyup更频繁触发的事件中,如resize, touchmove, mousemove, scroll。throttle
会强制函数以固定的速率执行。因此这个方法比较适合应用于动画相关的场景。节流与抖动的区别:demo
Debounce(去抖动)
这个术语来自电子学的领域,手动开关输入的信号被发送到数字电路中。在电子学中,当你按一个物理按钮一次,数字电路可能读到多个按压,因为按钮的物理属性(金属触点,弹簧,磨损件等)。
去抖动意味着采集到的所有这些波动的信号,并把它们当作一个。
所以我对防抖的理解是,在一定时间内,将触发了若干次的动作归为一次。而在另一篇文章中看到对防抖的定义是:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。要产生“重新计时”这个效果需利用clearTimeout。
var delta = 1000;
var timeoutID = null;
function log() {
console.log('foo');
}
function debouncedLog() {
clearTimeout(timeoutID); // 移除当前的setTimeout对象
timeoutID = setTimeout(function() {
// 重新建立一个setTimeout对象,此时的等待时间是重置了的
log();
}, delta);
};
window.onkeydown = debouncedLog;
对于clearTimeout的理解:执行setTimeout时会创建一个对象,在这里就是timeoutID,如果因为其他原因不想调用setTimeout了,可以利用clearTimeout(timeoutID)进行删除。这里能实现“重新计时”是因为每次调用setTimeout都会开始计时并且将setTimeout放入宏任务队列,而clearTimeout会移除宏任务队列里的setTimeout。