查看原文
其他

彻底弄懂 “ 防抖 和 节流 ”

前端小贾 前端学苑 2021-07-15

关注“前端学苑” ,坚持每天进步一点点


「~防抖和节流解析~」

试想一下,浏览器的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时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。


函数节流:使得一定时间内只触发一次函数。原理是通过判断是否到达一定时间来触发函数。

推荐热门技术文章:

1、一篇文章,教你学会Git

2、初探 Electron 桌面应用 - 理论篇

3、解锁 Webpack,看这篇就够了

4、干货:前端开发常见规范

5、这一次,彻底弄懂 Promise

6、关于移动端适配,你必须要知道的

7、你还是只会 npm install 吗?

8、让程序员变懒的 “vue-admin-template” 后台管理系统

9、这样配置,让你的VS Code好用到飞起!

10、前端性能优化实战

觉得本文对你有帮助?请分享给更多人

关注「前端学苑」加星标,提升前端技能

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存