Github 代碼:https://github.com/Haixiang6123/debounce-throttle
預覽:http://yanhaixiang.com/debounce-throttle/
debounce 和 throttle 是面試時經常會被問到的一道 JS 題。我自己在第一次找工作的時候,就被問過。當時被問得半天說不出兩者的區別,說着說着就把自己帶入坑了。
今天就跟大家分享一下這兩者的區別吧。
debounce 是什麼
中文名:防抖。在開始操作了之後,那麼只有在一段 delay 時間段後不再有操作了,才執行操作。
const onClick = debounce(fn, 300)
click // 不執行 fn
click // 不執行 fn
等 200 ms 後再 click // 不執行 fn
等 500 ms 後再 click // 執行 fn
相信大家上初中物理都見過音叉
當有東西碰到它的時候,就會一直在震,防抖可以形象地理解爲:當不再震動的時候做一些事情。
最常見的場景就是用戶不斷點擊“提交”按鈕,debounce 生成的函數就可以在用戶一段時間內不再點擊時,再執行“提交”操作。
debounce 實現
實現思路如下:
- setTimeout 在 delay ms 後執行
- 每次調用 debounced 函數時,都直接清除掉 timerId
- 當一段時間過去了(大於 delay ms),setTimeout 就會自動執行 fn
function debounce(fn, delay) {
let timerId, context, args
function debounced() {
[context, args] = [this, arguments]
clearTimeout(timerId) // 以後再次調用的時候會清除掉
timerId = setTimeout(() => {
fn.apply(context, arguments) // 到點執行
}, delay)
}
return debounced
}
throttle 是什麼
中文名:節流。在開始操作之後,在 delay ms 內只會做一次。
const onMove = throttle(fn, 300)
move // 第一次先執行
move // 300 ms 後執行 fn
過了 3 ms 後 move // 準備在 303 ms 執行 fn
過了 100 ms 後 move // 將上一次的 timerId 去掉,準備 400 ms 執行 fn
過了 301 ms 後 move // 馬上執行 fn
節流,字面意思就可以理解爲 threshold ms 一段時間裏做一件事,類似於技能的 CD。當然,這麼來理解可能不太準確的,因爲 throttle 還有一個條件就是最多執行一次。比如,在 CD 值冷卻的時候去執行,雖然現在執行不了,但是會在 delay ms 執行。
只有在無限多次執行上面的 move 纔會出現 threshold ms 後再執行一次的技能 CD 效果。
throttle 實現
實現思路如下:
- 第一次調用的時候就執行了
- 當上一次時間 + threshold > 當前時間(CD 值在冷卻)時調用,會在 thresold ms 後執行
- 執行 fn 時會記錄當前時間爲 preivous
function throttle(fn, threshold) {
let timerId, previous
function throttled() {
let [context, args] = [this, arguments]
const now = Date.now() // 記錄當前時間
if (previous && now < previous + threshold) {
clearTimeout(timerId) // 以後調用時,清除時間
timerId = setTimeout(() => { // 重新計時
previous = now // 記錄時間用於以後的比較
fn.apply(context, args)
}, threshold)
} else {
previous = now //記錄時間用於以後的比較,開始一段新的時間段
fn.apply(context, args)
}
}
return throttled
}