diff --git a/function/function.go b/function/function.go index 437c34e..9171305 100644 --- a/function/function.go +++ b/function/function.go @@ -70,6 +70,23 @@ func Delay(delay time.Duration, fn interface{}, args ...interface{}) { invokeFunc(fn, args...) } +// Debounced creates a debounced function that delays invoking fn until after wait duration have elapsed since the last time the debounced function was invoked. +func Debounced(fn func(), duration time.Duration) func() { + timer := time.NewTimer(duration) + timer.Stop() + + go func() { + for { + select { + case <-timer.C: + go fn() + } + } + }() + + return func() { timer.Reset(duration) } +} + // Schedule invoke function every duration time, util close the returned bool chan func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool { // Catch programming error while constructing the closure diff --git a/function/function_test.go b/function/function_test.go index 5ab909b..98f53f5 100644 --- a/function/function_test.go +++ b/function/function_test.go @@ -93,6 +93,28 @@ func TestDelay(t *testing.T) { Delay(2*time.Second, print, "test delay") } +func TestDebounced(t *testing.T) { + assert := internal.NewAssert(t, "TestDebounced") + + count := 0 + add := func() { + count++ + } + + debouncedAdd := Debounced(add, 50*time.Microsecond) + debouncedAdd() + debouncedAdd() + debouncedAdd() + debouncedAdd() + + time.Sleep(100 * time.Millisecond) + assert.Equal(1, count) + + debouncedAdd() + time.Sleep(100 * time.Millisecond) + assert.Equal(2, count) +} + func TestSchedule(t *testing.T) { assert := internal.NewAssert(t, "TestSchedule")