BetaThis is a live doc! Anyone with edit access can make updates in real time without having to publish.
By Bryan

尽管 Throttle / Debounce 在前端领域用的比较多且本文也用了 JS 举例,但是实际上这个术语是通用的,后端等也会使用

核心区别

  • Debounce:在事件被触发 n 秒后再执行回调,如果在这 n 秒内又被触发,则重新从新的时间开始计时 n 秒,直至连续的 n 秒没有新的触发事件发生时才会执行回调

    • immediate = true:在首次触发事件时立刻执行回调一次

  • Throttle:在事件被首次触发时立刻执行回调,后续的 n 秒出现新的事件时直接忽略

应用场景

  • 基于用户输入进行实时展示:debounce

  • 防止用户连续点击按钮触发多个事件:throttle

  • 滚动事件处理:throttle

实现代码(以 JS 为例)

Throttle

1function throttle(fn, delay) { 2 let lastTime = 0; 3 4 return function (...args) { 5 const now = Date.now(); 6 7 if (now - lastTime >= delay) { 8 fn.apply(this, args); 9 lastTime = now; 10 } 11 }; 12}

Debounce

1function debounce(fn, delay, immediate = false) { 2 let timer = null; 3 4 return function (...args) { 5 const callNow = immediate && !timer; 6 7 clearTimeout(timer); 8 9 timer = setTimeout(() => { 10 timer = null; 11 if (!immediate) { 12 fn.apply(this, args); 13 } 14 }, delay); 15 16 if (callNow) { 17 fn.apply(this, args); 18 } 19 }; 20}

如果始终 immediate=false,可以简化

1function throttle(fn, delay) { 2 let timer = null; 3 4 return function (...args) { 5 if (timer) { 6 return; 7 } 8 9 timer = setTimeout(() => { 10 fn.apply(this, args); 11 timer = null; 12 }, delay); 13 }; 14}

如果始终 immediate=true,可以简化

1function throttle(fn, delay) { 2 let timer = null; 3 4 return function (...args) { 5 if (timer) { 6 return; 7 } 8 9 fn.apply(this, args); 10 11 timer = setTimeout(() => { 12 timer = null; 13 }, delay); 14 }; 15} 16

补充

throttle 和 debounce(immediate=true) 有什么区别?

二者同样会立刻执行,但是在连续不停触发事件时候,throttle 保证了每隔单位时间都会触发一次,而 debounce(immediate=true) 则在后续不会再触发事件

1假设 delay = 1000ms,持续触发事件: 2 3throttle: 4时间轴: 0ms 1000ms 2000ms 3000ms 5执行: 执行 执行 执行 执行 6事件: | | | | | | | | | | | | | | | | 7 8debounce(immediate=true): 9时间轴: 0ms 1000ms 2000ms 3000ms 10执行: 执行 (无) (无) (无) 11事件: | | | | | | | | | | | | | | | | 1213 第一次执行后,后续的触发都被忽略,直到停止触发并等待1000ms后再触发新事件才会执行