防抖和节流
事件高频触发的场景
在JavaScript编程中,如果某个事件在短时间内高频触发,可能就会出现对应的 回调函数 响应速度跟不上调用频率的问题,导致页面延迟,假死或卡顿的现象,
函数防抖(debounce) 函数节流(throttle) 就是这类场景下常用的优化手段,来节约系统资源,改善用户体验。
原理
- 函数防抖(debounce):一定时间内,只会执行最后一次函数回调
- 函数节流(throttle):一定时间内,只执行一次函数回调
函数防抖的适用场景 —— 搜索查询
- 函数防抖:高频事件触发后,经过一定的时间间隔才会执行函数回调;如果事件在事件间隔内又被触发,则会重新计时,只会执行最后一次的回调函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
function debounce(fn, delay) { let timer = null return function () { console.log('timer', timer) if (timer) { clearTimeout(timer) } timer = setTimeout(fn, delay) } }
function inputTap(e) { console.log(e.target.value) }
document.addEventListener('input', debounce(inputTap, 1000))
|
函数节流的使用场景 —— 监听滚动条
- 函数节流:连续触发事件但在一定时间内只执行一次函数
节流的两种方式:时间戳和定时器
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const throttle = function (fn, delay) { let preTime = Date.now() return function () { let doTime = Date.now() if (delay <= doTime-preTime) { fn.apply(this, arguments)
preTime = Date.now() } }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const throttle = function (fn, delay) { let timer = null return function () { if (!timer) { timer = setTimeout(() => { fn.apply(this, arguments) clearTimeout(timer) timer = null }, delay) } } }
|
1 2 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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| function debounce() { var lastCallTime var lastThis var lastArgs var timeId wait = +wait || 0
function startTimer(timerExpired, wait) { return setTimeout(timerExpired, wait) }
function invokeFunc() { timeId = undefined const args = lastArgs const thisArg = lastThis let result = func.apply(thisArg, args)
lastArgs = lastThis = undefined return result }
function shouldInvoke(time) { return lastCallTime !== undefined && (wait <= time - lastCallTime) }
function remainingWait(time) { const timeSinceLastCall = time - lastCallTime const timeWaiting = wait - timeSinceLastCall return timeWaiting
} }
function timerExpired() { const time = Date.now() if (shouldInvoke(time)) { return invokeFunc() } timeId = startTimer((timerExpired, remainingWait(time)) }
function debounced(...args) { const time = Date.now() lastThis = this lastArgs = args lastCallTime = time
if (timeId === undefined) { timeId = startTimer(timerExpired, wait) }
}
return debounced }
|