欢迎学习交流!!!
持续更新中…
文章目录
- 防抖
- 节流
- 二者区别
- 应用场景
防抖和节流都是为了项目优化而出现的,官方没有具体定义的,他们的出现主要是为了解决一些短时间内连续执行的事件带来性能上的不佳和内存的消耗巨大等问题;像这类事件一般像 scroll keyup mousemove resize等等,短时间内不断的触发,在性能上消耗是非常大的,尤其是一些改变DOM结构的操作
节流[throttle]与防抖[debounce]非常相似,都是让上述这类事件在规定的事件从不断的去触发更改成为规定的时间内触发多少次
问题引入:
问题1: 如果实现了dom拖拽功能,但是在绑定拖拽事件的时候发现每当元素稍微移动一点便触发了大量的回调函数,导致浏览器直接卡死,这个时候怎么办?
问题2:如果给一个按钮绑定了表单提交的post事件,但是用户有些时候在网络情况极差的情况下多次点击按钮造成表单重复提交,如何防止多次提交的发生?
为了应对如上场景,便出现了函数防抖和函数节流两个概念,总的来说:
这两个方法是在时间轴上控制函数的执行次数。
防抖
函数防抖(debounce):在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
生活中的实例: 如果有人进电梯(触发事件),那电梯将在10秒钟后出发(执行事件监听器),这时如果又有人进电梯了(在10秒内再次触发该事件),我们又得等10秒再出发(重新计时)。
当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。如下图,持续触发click事件时,并不执行handle函数,当1000毫秒内没有触发click事件时,才会延时触发click事件。

防抖代码:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>防抖</title>
</head>
<body><button id="debounce1">点我防抖!</button><script>window.onload = function() {// 1、获取这个按钮,并绑定事件var myDebounce = document.getElementById("debounce1");myDebounce.addEventListener("click", debounce(handle);}// 2、防抖功能函数,接受传参function debounce(fn) {// 4、创建一个标记用来存放定时器的返回值let timeout = null;return function() {// 5、每次当用户点击/输入的时候,把前一个定时器清除clearTimeout(timeout);// 6、然后创建一个新的 setTimeout,// 这样就能保证点击按钮后的 interval 间隔内// 如果用户还点击了的话,就不会执行 fn 函数timeout = setTimeout(() => {fn.call(this, arguments);}, 1000);};}// 3、需要进行防抖的事件处理function handle() {// 有些需要防抖的工作,在这里执行console.log("防抖成功!");}</script>
</body>
</html>
实现:

可以看到,当持续触发click事件时,事件处理函数handle只在停止滚动1000毫秒之后才会调用一次,也就是说在持续触发click事件的过程中,事件处理函数handle一直没有执行。意思就是:这件事儿需要等待,如果你反复催促,我就重新计时!
节流
函数节流(throttle):指定时间间隔内只会执行一次任务。
生活中的实例: 我们知道目前的一种说法是当 1 秒内连续播放 24 张以上的图片时,在人眼的视觉中就会形成一个连贯的动画,所以在电影的播放(以前是,现在不知道)中基本是以每秒 24 张的速度播放的,为什么不 100 张或更多是因为 24 张就可以满足人类视觉需求的时候,100 张就会显得很浪费资源。
规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。节流通俗解释就比如我们水龙头放水,阀门一打开,水哗哗的往下流,秉着勤俭节约的优良传统美德,我们要把水龙头关小点,最好是如我们心意按照一定规律在某个时间间隔内一滴一滴的往下滴。如下图,持续触发click事件时,并不立即执行handle函数,每隔1000毫秒才会执行一次handle函数。

节流代码:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>节流</title>
</head>
<body><button id="throttle">点我节流!</button><script>window.onload = function() {// 1、获取按钮,绑定点击事件var myThrottle = document.getElementById("throttle");myThrottle.addEventListener("click", throttle(sayThrottle));}// 2、节流函数体function throttle(fn) {// 4、通过闭包保存一个标记let canRun = true;return function() {// 5、在函数开头判断标志是否为 true,不为 true 则中断函数if(!canRun) {return;}// 6、将 canRun 设置为 false,防止执行之前再被执行canRun = false;// 7、定时器setTimeout( () => {fn.call(this, arguments);// 8、执行完事件(比如调用完接口)之后,重新将这个标志设置为 truecanRun = true;}, 1000);};}// 3、需要节流的事件function sayThrottle() {console.log("节流成功!");}</script>
</body>
</html>
实现:

二者区别
函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。 比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。
应用场景
对于函数防抖,有以下几种应用场景:
- 给按钮加函数防抖防止表单多次提交。
- 对于输入框连续输入进行AJAX验证时,用函数防抖能有效减少请求次数。
- 判断scroll是否滑到底部,滚动事件+函数防抖
总的来说,适合多次事件一次响应的情况
对于函数节流,有如下几个场景:
- 游戏中的刷新率
- DOM元素拖拽
- Canvas画笔功能
总的来说,适合大量事件按时间做平均分配触发。
优秀文章:
JS的防抖与节流















