go 37 lines · 7 steps

Debouncing a stream of events in Go

A timer batches bursts of events and flushes them only after activity goes quiet for 200ms.

Explained by highlit
1func (w *Watcher) resetDebounce(d time.Duration) {
2 if !w.timer.Stop() {
3 select {
4 case <-w.timer.C:
5 default:
6 }
7 }
8 w.timer.Reset(d)
9}
10 
11func (w *Watcher) run(events <-chan Event) {
12 w.timer = time.NewTimer(time.Hour)
13 if !w.timer.Stop() {
14 <-w.timer.C
15 }
16 
17 var pending []Event
18 for {
19 select {
20 case ev, ok := <-events:
21 if !ok {
22 if len(pending) > 0 {
23 w.flush(pending)
24 }
25 return
26 }
27 pending = append(pending, ev)
28 w.resetDebounce(200 * time.Millisecond)
29 case <-w.timer.C:
30 w.flush(pending)
31 pending = pending[:0]
32 case <-w.quit:
33 w.timer.Stop()
34 return
35 }
36 }
37}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Debouncing collects rapid events and acts only after a quiet interval, avoiding redundant work.
  2. 2Draining a stopped timer's channel prevents stale ticks from firing a spurious flush.
  3. 3A single select loop cleanly multiplexes input, timeout, and shutdown signals.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Debouncing a stream of events in Go — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code