Skip to content

Instantly share code, notes, and snippets.

@byrnedo
Last active November 2, 2022 08:53
Show Gist options
  • Save byrnedo/1d6b852b62951f0e5f890eaac026daa4 to your computer and use it in GitHub Desktop.
Save byrnedo/1d6b852b62951f0e5f890eaac026daa4 to your computer and use it in GitHub Desktop.
Debounce go channel
package pkg
import (
"context"
"time"
)
// Debounce takes a channel, and will notify the output channel with the last received message at frequency min.
// Upon cancel or max timeout, it will check one last time for a message.
// Cancelling the ctx will cause the goroutine to exit.
// Surpassing the max duration will also.
// Calling the returned cancel function will also.
func Debounce[T any](ctx context.Context, min, max time.Duration, input <-chan T, output chan<- T) func() {
ctx, cncl := context.WithTimeout(ctx, max)
go func() {
defer cncl()
var (
buffer *T
minTimer = time.NewTimer(min)
flush = func() {
if buffer != nil {
// don't block if we couldn't send
select {
case output <- *buffer:
default:
}
buffer = nil
}
}
)
defer minTimer.Stop()
hits := 0
for {
select {
case <-ctx.Done():
// try and get last message
select {
case tmpBuf, ok := <-input:
if !ok {
break
}
buffer = &tmpBuf
default:
}
flush()
return
case tmpBuf, ok := <-input:
if !ok {
// eh, not sure what to do here
return
}
hits++
buffer = &tmpBuf
case <-minTimer.C:
flush()
minTimer.Reset(min)
}
}
}()
return cncl
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment