防抖 debounce
应用场景:监听一个输入框,文字变化触发change事件,不使用防抖,每次输入都会触发事件,使用防抖,等用户输入结束或暂停时才触发
<input type="text" class="input">
<script>
const input = document.querySelector('.input')
let timer = null
input.addEventListener('keyup', () => {
if (timer) {
window.clearTimeout(timer)
}
timer = setTimeout(() => {
console.log(input.value)
timer = null
}, 500)
})
</script>
封装成函数
<input type="text" class="input">
<script>
const input = document.querySelector('.input')
function debounce(fn, delay = 500) {
let timer = null
return function() {
const context = this
if (timer) {
window.clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(context, arguments)
timer = null
}, delay)
}
}
input.addEventListener('keyup', debounce(() => { console.log(input.value) }))
</script>
节流 throttle
应用场景:拖拽一个元素时,要随时拿到该元素的拖拽位置,如果不想频繁触发导致卡顿,应使用节流,不论拖拽速度有多快,每隔100ms触发一次; 或者监听用户点击按钮,在一定时间内只有1次有效
<div class="div" draggable="true"></div>
<script>
const div = document.querySelector('.div')
let timer = null
div.addEventListener('drag', (e) => {
if (timer) {
return
}
timer = setTimeout(()=> {
console.log(e.offsetX, e.offsetY)
timer = null
}, 100)
})
</script>
封装成函数
<div class="div" draggable="true"></div>
<script>
const div = document.querySelector('.div')
function throttle(fn, delay = 100) {
let timer = null
return function () {
const context = this
if (timer) {
return
}
timer = setTimeout(() => {
fn.apply(context, arguments)
timer = null
}, delay)
}
}
div.addEventListener('drag', throttle((e) => {
console.log(e.offsetX, e.offsetY)
}))
</script>
节流写法二
function throttle(fn, delay=3000) {
let canUse = true
return function() {
if (canUse) {
canUse = false
fn.apply(this, arguments)
window.setTimeout(() => canUse = true, delay)
}
}
}
const f = throttle((a) => console.log(a))
f(1)
f(1) // 不会执行