什么是防抖?
防抖就是对于频繁触发的事件添加一个延时同时设定一个最小触发间隔,如歌触发间隔小于设定的间隔,则清除原来的定时,重新设定新的定时;如果触发间隔大于设定间隔,则保留原来的定时,并设置新的定时;防抖的结果就是频繁的触发转变为触发一次。
为什么要进行防抖?
在频繁触发事件的场景,有些情况可能执行的逻辑比较复杂或者耗时,此时浏览器的处理跟不上触发,就会发生卡顿、假死或者事件堆积,这里防抖就可以一定程度是哪个解决或者缓解这种故障。
常见需要防抖的场景:
- 搜索框 keyup、keydown 等触发后台请求;
- 频繁改变窗口大小 resize;鼠标移动mousemove事件;
类似以上频繁触发并且处理逻辑较为耗时或者触发时需要请求后台接口
如何做到防抖呢?
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <style> div{ width: 500px; height: 300px; background-color: orange; } </style> </head> <body> <div id="div"></div> <script> const div = document.getElementById('div') const debounce = (fn, wait) => { let timer = null return function(){ clearTimeout(timer) timer = setTimeout(()=>{ fn.apply(this, arguments) }, wait) } } const fn = debounce(e=>{ console.log('move', e) }, 1000) div.addEventListener('mousemove', fn) </script> </body>
执行结果:在橙色区域移动鼠标,只在停止移动后才会触发一次事件
如果我们想让事件立即触发一次呢?
const div = document.getElementById('div') const debounce = (fn, wait, immediate = false) => { let timer = null return function(){ if(timer) clearTimeout(timer) if(immediate){ let trigger = !timer timer = setTimeout(()=>{ timer = null }, wait) if(trigger){ fn.apply(this, arguments) } return } timer = setTimeout(()=>{ fn.apply(this, arguments) }, wait) return } } const fn = debounce(e=>{ console.log('move', e) }, 1000, true) div.addEventListener('mousemove', fn)
执行结果是:立即触发一次,然后停止触发1s后才能再次触发