feat(debounce): add doc + accept multiple callback functions

This commit is contained in:
Samuel Berthe
2022-03-20 01:46:33 +01:00
parent ecdd8512f4
commit 9abdcd40ea
2 changed files with 45 additions and 35 deletions

View File

@@ -796,26 +796,24 @@ iter, err := lo.Attempt(0, func(i int) error {
// nil
```
For more advanced retry strategies (delay, exponential backoff...), please take a look on [cenkalti/backoff](https://github.com/cenkalti/backoff).
### Debounce
creates a debounced instance that delays invoking func given until after wait milliseconds have elapsed.
`NewDebounce` creates a debounced instance that delays invoking functions given until after wait milliseconds have elapsed, until `cancel` is called.
```go
f := func() {
println("1. Called once after 100ms when func stopped invoking!")
println("Called once after 100ms when debounce stopped invoking!")
}
d, cancel := lo.NewDebounce(100 * time.Millisecond, f)
// f is invoked only 3 times
for i := 0; i < 3; i++ {
// No matter how many times you call it, it will be invoked only the last time after 100ms
for j := 0; j < 10; j++ {
d()
}
time.Sleep(200 * time.Millisecond)
debounce, cancel := lo.NewDebounce(100 * time.Millisecond, f)
for j := 0; j < 10; j++ {
debounce()
}
time.Sleep(1 * time.Second)
cancel()
// f will never be invoked again
for i := 0; i < 3; i++ {
d()
}
```
### Range / RangeFrom / RangeWithSteps
@@ -846,8 +844,6 @@ result := Range(0);
// []
```
For more advanced retry strategies (delay, exponential backoff...), please take a look on [cenkalti/backoff](https://github.com/cenkalti/backoff).
## 🛩 Benchmark
We executed a simple benchmark with the a dead-simple `lo.Map` loop:

View File

@@ -5,36 +5,61 @@ import (
"time"
)
type Debounce struct {
after time.Duration
mu *sync.Mutex
timer *time.Timer
done bool
type debounce struct {
after time.Duration
mu *sync.Mutex
timer *time.Timer
done bool
callbacks []func()
}
func (d *Debounce) add(f func()) *Debounce {
func (d *debounce) reset() *debounce {
d.mu.Lock()
defer d.mu.Unlock()
if d.done {
return d
}
if d.timer != nil {
d.timer.Stop()
}
d.timer = time.AfterFunc(d.after, f)
d.timer = time.AfterFunc(d.after, func() {
for _, f := range d.callbacks {
f()
}
})
return d
}
func (d *Debounce) cancel() {
func (d *debounce) cancel() {
d.mu.Lock()
defer d.mu.Unlock()
if d.timer != nil {
d.timer.Stop()
d.timer = nil
}
d.done = true
}
// NewDebounce creates a debounced instance that delays invoking functions given until after wait milliseconds have elapsed.
func NewDebounce(duration time.Duration, f ...func()) (func(), func()) {
d := &debounce{
after: duration,
mu: new(sync.Mutex),
timer: nil,
done: false,
callbacks: f,
}
return func() {
d.reset()
}, d.cancel
}
// Attempt invokes a function N times until it returns valid output. Returning either the caught error or nil. When first argument is less than `1`, the function runs until a sucessfull response is returned.
func Attempt(maxIteration int, f func(int) error) (int, error) {
var err error
@@ -51,14 +76,3 @@ func Attempt(maxIteration int, f func(int) error) (int, error) {
}
// throttle ?
// NewDebounce creates a debounced instance that delays invoking func given until after wait milliseconds have elapsed.
func NewDebounce(duration time.Duration, f func()) (func(), func()) {
d := &Debounce{
mu: new(sync.Mutex),
after: duration,
}
return func() {
d.add(f)
}, d.cancel
}