事件處理的常見問題,短時間內事件發生太頻繁,接收端處理不了,卡死、噴錯或其他,要用一些手法來減壓。

日常使用 Vim 會碰到嗎?幾乎不會,多半 plugin 會自己照顧自己,其次是症狀不夠嚴重,所以無感;最後是真的爆了,也懶得追怎麼回事,quit 重開復原,那些殺不死我的,我就不修。

然而 autocmd 越寫越多,各種自動化疊來疊去,看似無害的事件(例如 User xxx)也可能在跑某個 script 時(例如 :source $VIMRUNTIME/syntax/hitest.vim)突然爆發——幸好要解決也不難,就是用 timer_* 系列函數。


辨別 debounce / throttle

不就是要抑制事件的觸發嗎?為何變成只有 debounce / throttle 兩個選項呢?

其實根據需求,會有多樣的操作才對,例如 ReactiveX 定義的各種 filter 運算就可以參考(只是借用,概念不盡相同); 而一般應用上,最直觀以「一段時間」為限,降低頻率的作法,就能歸納為 throttle

至於 debounce 就比較難翻譯,或說看字面難以想像,先來考察用語來源:

  • 最早來自電路開關的彈跳 (bounce) 現象,要判斷是實際輸入,還是零件振動的雜訊,解法不只一種。 wikipedia: Switch
  • 承上,一種解法:訊號發生後,短時間內的訊號先不理會,然後就能正確判定了——常見例子是鍵盤。 wikipedia: Keyboard
  • JavaScript 開發者的引用,意思是將多個連續發生的訊號「合併」為一個訊號,見 Debouncing Javascript Methods | John Hann
    Debouncing means to coalesce several temporally close signals into one signal.
    具體實作會設定一段時間,期間內再度發生事件的話,就重新計時,直到超過這段時間都沒有發生,才認定整個事件完成。

我自己看這個詞,在程式領域的用法已經特化了——主要概念仍是消除不穩定,而作法是等,特徵是等的時間可以延長,描述為一個意象的話,是等一個振動的東西穩定下來。

這個認知下,即便 Lodash 的 throttle 是用 debounce 做的(採 maxWait = wait 的設定),也不會說 throttle 是 debounce 的一種,反而應該說不能延長 wait 的用法其實指的是 throttle。


...攤開這篇文章繼續閱讀關閉