一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第18天,点击查看活动详情。
经历过黎明前的黑暗,就能迎来那最美的曙光。
防抖和截流在日常开发中是经常用到的知识,但是呢,很多人包括我在内很容易将这两个概念混淆。虽然用的时候不会存在问题,但一涉及到概念常常犯懵。今天就用一种自己理解的形式记录一下两者常用的场景和区别。
防抖
理解
什么是防抖呢?它字面的含义就是防止抖动,这个防止并不是不允许,而是在你抖动的时候,我不会进行接下来的操作,直到你不再抖动或者暂停抖动,我才会继续接下来的操作。防抖呢,关键记住的就是抖,下面我们来看一张图片。
图片中绿色的表示在进行抖动或者说是在进行事件触发,但是呢,因为做了防抖,我需要等待一段时间(停止或者暂停抖动)才会真正的触发事件(进行下一步操作)。
只要你两次触发事件的时间间隔小于等待时间,无论你连续触发多少次,我只会在等待时间中未在此触发事件的时机才会真正的触发事件
举例
输入框,当停止输入的时候才会进行下一步操作。比如我们做的程序中有一个搜索框,当用户在输入框中听着输入的时候,我们根据用户输入的内容,在下方显示用户的订单。这里就应该用防抖,不然用户每输入一个文字,就搜索一次,一般公司的服务器压力会很大,而且页面的实际呈现效果并不好。
代码
debounce&throttle.html
<!--防抖-->
搜索: <input type="text" id="input1">
<script>
function debounce(fn, delay=200){//一般防抖做200ms就可以,也可以根据实际情况进行设置
let timer = 0;
return function(){
if(timer) clearTimeout(timer)//如果存在定时器,直接清除
timer = setTimeout(() => {
fn.apply(this, arguments)//透传this
timer = 0;//将定时器再次清零
}, delay)
}
}
const input1 = document.getElementById("input1");
const fn = () => { console.log(input1.value) }
input1.addEventListener('keyup',debounce(fn))//这里delay使用默认的200ms
当连续多次快速(小于200ms)在输入框中输入时,控制台并不会打印,直到下次输入与这次输入间隔时间大于200ms的时候,控制台才会打印出输入框中的内容。
节流
理解
无法开源只能节流,这里的节流就是节省交互沟通,固定时间触发一次。我不管你怎样操作,在固定的时间内,我只会进行一次操作,其他进来的操作一律打回,不接待。
上图中蓝色表示在固定时间内多次触发了事件,但是我只执行绿色的,也就是在这段时间内我只触发本段时间内第一次的触发事件,其他的,该哪儿去哪儿去,老子不接待。
举例
当我们需要监听滚动事件元素位置的时候,或者拖拽元素的位置的时候,最好理解的可能是我们的获取验证码吧。在固定时间内,只能点击一次,在不考虑按钮置灰的样式问题,它就是一个节流,在相同时间内,无论你点击多少次,我只触发一次验证码的请求事件。
代码
<!--节流-->
debounce&throttle.html
<div id="div1" draggable="true" style="width: 50px;height: 50px;background-color: #ccc;">hellow</div>
<script>
function throttle(fn,delay=100){//节流一般设置为100ms
let timer = 0;
return function(){
if(timer) return //如果timer存在,不在向下继续执行
timer = setTimeout(() => {
fn.apply(this, arguments)//透传this
timer = 0;//将定时器再次清零
}, delay)
}
}
const div1 = document.getElementById("div1");
const fn1 = (e) => console.log(e.offsetX)
div1.addEventListener('drag',fn1)
// div1.addEventListener('drag',throttle(fn1))
</script>
执行上方代码,连续拖动div的时候,你会发现在浏览器的控制台打印出的offsetX的前方存在另外一个数字,说明同一个位置,打印了多次,就像下方图片展示一样
;
如果将注释的代码打开,将注释代码上方一行代码注释掉,在此连续拖动div,你会发现offsetX的前方的数字消失了。如果将delay的时间改的足够大,甚至会打印变得更少
总结
防抖和截流的概念和理解上的问题已经说的差不多了,让我们仔细看一下代码,仔细看你其实就会发现,这两个函数的代码只存在些许差别:
防抖: if(timer) clearTimeout(timer)//如果存在定时器,直接清除,如果存在定时器,我就将已经存在的清除掉,不执行 。上升到理论就是你不抖,我就执行,你抖动,我就不动。敌不动我动,敌动我不动(注意时间)。
截流:if(timer) return //如果timer存在,不在向下继续执行,如果存在定时器,我就只执行存在的定时器中的代码,再这段代码执行期间进来的,都哪儿来哪儿去,别来烦我。上升到理论就是,在一段时间内,我只在乎第一个,其他的我都不管。