函数防抖和节流,都是控制事件触发频率的方法。应用场景有很多,输入框持续输入,将输入内容远程校验、多次触发点击事件、onScroll等等。
防抖
函数防抖,这里的抖动就是执行的意思,而一般的抖动都是持续的,多次的。假设函数持续多次执行,我们希望让它冷静下来再执行。也就是当持续触发事件的时候,函数是完全不执行的,等最后一次触发结束的一段时间之后,再去执行。
分解一下需求:
持续触发不执行
不触发的一段时间(最后一次点击)之后再执行
那么怎么实现上述的目标呢?我们先看这一点:在不触发的一段时间之后再执行,那就需要个定时器呀,定时器里面调用我们要执行的函数,将arguments传入。
封装一个函数,让持续触发的事件监听是我们封装的这个函数,将目标函数作为回调(func)传进去,等待一段时间过后执行目标函数
| 12
 3
 4
 5
 6
 7
 8
 
 | function debounce(func, delay) {
 return function() {
 setTimeout(() => {
 func.apply(this, arguments)
 }, delay)
 }
 }
 
 | 
第二点实现了,再看第一点:持续触发不执行。我们先思考一下,是什么让我们的函数执行了呢?是上边的setTimeout。OK,那现在的问题就变成了持续触发,不能有setTimeout。这样直接在事件持续触发的时候,清掉定时器就好了。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | function debounce(func, delay) {let timeout
 return function() {
 clearTimeout(timeout)
 timeout = setTimeout(() => {
 func.apply(this, arguments)
 }, delay)
 }
 }
 用法:
 
 box.onmousemove = debounce(function (e) {
 box.innerHTML = `${e.clientX}, ${e.clientY}`
 }, 1000)
 
 
 | 
节流
节流的意思是让函数有节制地执行,而不是毫无节制的触发一次就执行一次。什么叫有节制呢?就是在一段时间内,只执行一次。
同样,我们分解一下:
持续触发并不会执行多次
(第一次执行之后)到一定时间再去执行
思考一下,持续触发,并不会执行,但是到时间了就会执行。抓取一个关键的点:就是执行的时机。要做到控制执行的时机,我们可以通过一个开关,与定时器setTimeout结合完成。
函数执行的前提条件是开关打开,持续触发时,持续关闭开关,等到setTimeout到时间了,再把开关打开,函数就会执行了。
我们看一下代码怎么实现:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | function throttle(func, delay) {let run = true
 return function () {
 if (!run) {
 return
 }
 run = false
 setTimeout(() => {
 func.apply(this, arguments)
 run = true
 }, delay)
 }
 }
 
 | 
调用的时候:
| 12
 3
 4
 
 | box.onmousemove = throttle(function (e) {box.innerHTML = `${e.clientX}, ${e.clientY}`
 }, 1000)
 
 
 | 
这样,就实现了节流,节流还可以用时间间隔去控制,就是记录上一次函数的执行时间,与当前时间作比较,如果当前时间与上次执行时间的时间差大于一个值,就执行。
总结
防抖和节流巧妙地用了setTimeout,来控制函数执行的时机,优点很明显,可以节约性能,不至于多次触发复杂的业务逻辑而造成页面卡顿。
介绍节流防抖原理、区别以及应用
防抖:多次触发事件,事件处理函数只能执行一次,并且是在触发操作结束时执行。也就是说,当一个事件被触发准备执行事件函数前,会等待一定的时间(这时间是码农自己去定义的,比如 1 秒),如果没有再次被触发,那么就执行,如果被触发了,那就本次作废,重新从新触发的时间开始计算,并再次等待 1 秒,直到能最终执行
节流:事件触发后,规定时间内,事件处理函数不能再次被调用。也就是说在规定的时间内,函数只能被调用一次,且是最先被触发调用的那次
使用场景
防抖:搜索框搜索输入,并在输入完以后自动搜索、手机号,邮箱验证输入检测、窗口大小 resize 变化后,再重新渲染。
节流:滚动加载更多、搜索框搜的索联想功能、高频点击、表单重复提交……
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 
 | 
 
 
 
 
 function debounce(fn, delay) {
 
 var timer = null;
 return function () {
 
 clearTimeout(timer);
 
 timer = setTimeout(function(){
 
 fn.apply(this);
 }, delay);
 }
 }
 document.getElementById('btn').onclick = debounce(function () {
 console.log('按钮被点击了' + Date.now());
 }, 1000);
 * 节流函数 一个函数执行一次后,只有大于设定的执行周期才会执行第二次。有个需要频繁触发的函数,出于优化性能的角度,在规定时间内,只让函数触发的第一次生效,后面的不生效。
 
 
 * @param fn要被节流的函数
 * @param delay规定的时间
 */
 function throttle(fn, delay) {
 
 var lastTime = 0;
 return function(){
 
 var nowTime = Date.now();
 if(nowTime - lastTime > delay){
 
 fn.call(this);
 
 lastTime = nowTime;
 }
 }
 }
 
 document.onscroll = throttle(function () {
 console.log('scllor事件被触发了' + Date.now());
 }, 200);
 
 
 
 | 
参考文章:函数的防抖和节流是个啥???
介绍节流防抖原理、区别以及应用