我自问这辈子没做过坏事,为什么要被生活勒住喉咙。—— 网易云热评《父亲的散文诗》
关于防抖和节流这一部分功能,最难的地方也是最重要的地方就是闭包的使用。
防抖 debounce
防抖,就是指在触发事件之后 n 秒内只能执行一次,如果 n 秒内又触发了事件,则会重新计算函数执行时间。
想象这样一种情况,当你点击一个按钮时,你本来想点一次,但是鼠标接触过于优良连点了两次,就会造成两次数据提交。这种时候就需要用到我们的防抖了。
所以防抖一般常用在提交表单时。
防抖有两种,一种是非立即执行版,一种是立即执行版
非立即执行
非立即执行版的意思是触发事件后函数不会立即执行,而是在 n 秒后执行,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <body> <button id="btn">submit</button> <script> function debounce(fn, wait) { let timeout = null return function() { if (timeout !== null) { clearTimeout(timeout) } timeout = setTimeout(fn, wait) } }
function submit() { console.log(2) } document.getElementById('btn').onclick = debounce(submit, 1000) </script> </body>
|
立即执行
立即执行版的意思是触发事件后函数会立即执行,然后 n 秒内不触发事件才能继续执行函数的效果。
1 2 3 4 5 6 7 8 9 10 11 12 13
| function debounce(fn, wait) { let timeout = null return function() { if (timeout !== null) { clearTimeout(timeout) } let callNow = !timeout timeout = setTimeout(function() { timeout = null }, wait) if (callNow) fn() } }
|
在这里我们发现,无论是非立即执行还是立即执行,我们都需要去清除上一次的 setTimeout,如果不清除,到了约定时间它还是会执行。
我们还可以给 debounce 函数加多一个参数用来控制非立即执行还是立即执行,以方便我们的不同需求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function debounce(fn, wait, immediate) { let timeout = null return function() { if (timeout !== null) { clearTimeout(timeout) } if (immediate) { let callNow = !timeout timeout = setTimeout(function() { timeout = null }, wait) if (callNow) fn() } else { timeout = setTimeout(fn, wait) } } }
|
节流 throttle
节流,就是指连续触发事件,但是 n 秒内只执行一次函数。节流会稀释函数的执行频率。
相较起来,节流写起来会比防抖容易些。
1 2 3 4 5 6 7 8 9 10 11
| function throttle(fn, wait) { let timeout = null return function() { if (!timeout) { timeout = setTimeout(() => { timeout = null fn() }, wait); } } }
|