节流和防抖都是为了解决短时间内多次触发某事件,而造成的性能问题。由于实现原理不同,决定了它们适用于不同的场景。
# 1. 防抖
# 原理
防抖
是通过维护一个计时器,规定时间结束才会触发事件回调,而规定时间内再次操作时,会清除当前的计时器并重新开始计时,从而保证只有最后一次操作才会被执行。
# 适用场景
- 连续输入,触发 ajax 查询。eg.输入框联想功能
- 拖动元素或调整窗口大小,触发事件。eg.拖动 div 计算最终放置的坐标位置
**共性:**无需关注中间环节,仅在意最后那一次的操作所能触发的事件响应。
# 实现
以 输入框联想功能 为例:
<input type="text" name="input" id="input">
<script>
// 模拟ajax请求
function ajax(content) {
console.log('ajax request ' + content)
}
// 封装防抖函数
function debounce(fun, delay) {
let timer = null
// 通过闭包避免定义全局变量 timer
return function (args) {
// 每次触发,都会清除当前的 timer,然后重写开始计时
clearTimeout(timer)
timer = setTimeout(() => {
fun(args)
}, delay)
}
}
let input = document.getElementById('input')
// 获取防抖回调函数
let cbDebounce = debounce(ajax, 500)
input.addEventListener('keyup', (e) => {
cbDebounce(e.target.value)
})
</script>
# 2. 节流
# 原理
节流
是保证规定时间范围内,只触发一次事件回调。
# 适用场景
- 连续滚动,触发 ajax 查询。eg.滚动加载(实则是数据翻页,每一页数据都不容忽视)
- 连续点击按钮触发某事件,只在规定时间内触发一次
**共性:**连续操作中的中间节点不容忽视,需要获取其中每个有效节点的事件响应。
# 实现
以 列表滚动加载 为例: // 模拟ajax请求 function ajax(content) { console.log('ajax request ' + content) }
// 1. 时间戳版(规定时间开始时触发)
function throttle(fun, delay) {
let preTime = 0 // 上次触发的时间(戳)
return function() {
let that = this
let _args = arguments
let now = Date.now() // 当前时间(戳)
if (now - preTime > delay) {
preTime = now
fun.apply(that, _args)
}
}
}
// 2. 定时器版(规定时间结束时触发)
function throttle(fun, delay) {
let timer = null
return function() {
let that = this
let _args = arguments
if (!timer) {
timer = setTimeout(() => {
timer = null
fun.apply(that, _args)
}, delay)
}
}
}
// 获取节流回调函数
let cbThrottle = throttle(ajax, 500)
window.addEventListener('scroll', () => {
cbThrottle()
})