彻底弄懂 “ 防抖 和 节流 ”
关注“前端学苑” ,坚持每天进步一点点
「~防抖和节流解析~」
试想一下,浏览器的resize、scroll、keypress、mousemove操作时会频繁触发,如果我们在回调中计算元素位置、做一些跟DOM相关的操作,引起浏览器回流和重绘,频繁触发回调,很可能会造成浏览器掉帧,甚至会使浏览器崩溃,影响用户体验。针对这种现象,目前有两种常用的解决方案:防抖和节流。
一、定义
1、防抖(debounce)
防抖 — 指触发事件后,就是把触发非常频繁的事件合并成一次去执行。
即在指定时间内只执行一次回调函数,如果在指定的时间内又触发了该事件,则回调函数的执行时间会基于此刻重新开始计算。
以我们生活中乘车刷卡的情景举例,只要乘客不断地在刷卡,司机师傅就不能开车,乘客刷卡完毕之后,司机会等待几分钟,确定乘客坐稳再开车。如果司机在最后等待的时间内又有新的乘客上车,那么司机等乘客刷卡完毕之后,还要再等待一会,等待所有乘客坐稳再开车。
如图:
2、节流(throttle)
节流 — 指频繁触发事件时,只会在指定的时间段内执行事件回调,即触发事件间隔大于等于指定的时间才会执行回调函数。
类比到生活中的水龙头,拧紧水龙头到某种程度会发现,每隔一段时间,就会有水滴流出。
如图:
区别:防抖动和节流的本质是不一样的。防抖动是将多次执行变为最后一次执行,节流是将多次执行变成每隔一段时间执行。
二、实现代码
1、防抖(debounce)
使用函数防抖来优化相关操作:
// 普通方案
window.addEventListener('resize', () => {
console.log('trigger');
})
优化方案:
// debounce 函数接受一个函数和延迟执行的时间作为参数
function debounce(fn, delay){
// 维护一个 timer
let timer = null;
return function() {
// 获取函数的作用域和变量
let context = this;
let args = arguments;
clearTimeout(timer);
timer = setTimeout(function(){
fn.apply(context, args);
}, delay)
}
}
function foo() {
console.log('trigger');
}
// 在 debounce 中包装我们的函数,过 2 秒触发一次
window.addEventListener('resize', debounce(foo, 2000));
1) 在 resize 事件上绑定处理函数,这时 debounce 函数会立即调用,实际上绑定的函数的 debounce 函数内部返回的函数。
2) 每一次事件被触发,都会清除当前的 timer 然后重新设置超时调用。
3) 只有在最后一次触发事件,才能在 delay 时间后执行。
2、节流(throttle)
时间戳方式:
使用时间戳的节流函数会在第一次触发事件时立即执行,以后每过 delay 秒之后才执行一次,并且最后一次触发事件不会被执行;
var throttle = function(func, delay){
var prev = Date.now();
returnfunction(){
var context = this;
var args = arguments;
var now = Date.now();
if(now-prev>=delay){
func.apply(context,args);
prev = Date.now();
}
}
}
定时器方式:
使用定时器的节流函数在第一次触发时不会执行,而是在 delay 秒之后才执行,当最后一次停止触发后,还会再执行一次函数。
var throttle = function(func, delay){
var timer = null;
returnfunction(){
var context = this;
var args = arguments;
if(!timer){
timer = setTimeout(function(){
func.apply(context, args);
timer = null;
},delay);
}
}
}
三、应用场景
1、防抖(debounce)
1)每次 resize/scroll 触发统计事件
2)文本输入的验证,连续输入文字后发送 AJAX 请求进行验证,验证一次就好。
2、节流(throttle)
1)DOM 元素的拖拽功能实现(mousemove)
2)搜索联想(keyup)
3)计算鼠标移动的距离(mousemove)
4)Canvas 模拟画板功能(mousemove)
5)射击游戏的 mousedown/keydown 事件(单位时间只能发射一颗子弹)
6)监听滚动事件判断是否到页面底部自动加载更多
总结
函数防抖:将几次操作合并为一次操作进行。原理是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。
函数节流:使得一定时间内只触发一次函数。原理是通过判断是否到达一定时间来触发函数。
推荐热门技术文章:
8、让程序员变懒的 “vue-admin-template” 后台管理系统
觉得本文对你有帮助?请分享给更多人
关注「前端学苑」加星标,提升前端技能