暴力
不防抖:每次调用都立刻执行。它满足"能调用"这个最低要求,但完全没有"安静 wait 后再执行"的语义。
取舍:零成本,但只能作为对照;连续调用会执行多次。
暴力写法
js1function debounce(fn, wait) {
2 return fn
3}
防抖:等安静下来再执行
连续调用时,只在最后一次调用之后安静 wait 毫秒,执行一次 fn;执行时使用最后一次调用的 this 和参数。
学习目标
能说清防抖和节流的区别,独立写出带闭包/this/参数处理的 debounce,并知道什么时候该补 cancel。
防抖和节流都能限制频率,它们的区别是什么?什么场景应该用防抖?
下面哪个场景最适合防抖?
建议先完成当前阶段(提示 / 检查 / 自评),再进入下一步;也可以直接跳过。
debounce(fn, wait) 返回一个包装函数;调用包装函数时可以传任意参数。
连续调用时,只在最后一次调用之后安静 wait 毫秒,执行一次 fn;执行时使用最后一次调用的 this 和参数。
不防抖:每次调用都立刻执行。它满足"能调用"这个最低要求,但完全没有"安静 wait 后再执行"的语义。
取舍:零成本,但只能作为对照;连续调用会执行多次。
用闭包保存 timer;每次调用先取消上一次,再安排新的定时器。只有最后一次调用的定时器能活到 wait。
取舍:满足大多数场景;但没有 cancel,组件卸载时无法主动取消,容易留下"幽灵执行"。
在常见方案上补 cancel;执行后把 timer 置空,避免"已经执行过,cancel 又触发"的状态歧义。
取舍:更完整;如果要 flush(立即执行挂起调用)还要再补一个方法。
连续调用只执行一次期望:count === 1
(async () => {
let count = 0
const d = debounce(() => count++, 20)
d(); d(); d()
await new Promise((r) => setTimeout(r, 60))
return count === 1
})()执行时使用最后一次调用的参数期望:got === 3
(async () => {
let got
const d = debounce((v) => { got = v }, 20)
d(1); d(2); d(3)
await new Promise((r) => setTimeout(r, 60))
return got === 3
})()安静 wait 后可以再次触发期望:count === 2
(async () => {
let count = 0
const d = debounce(() => count++, 10)
d()
await new Promise((r) => setTimeout(r, 40))
d()
await new Promise((r) => setTimeout(r, 40))
return count === 2
})()