File
Blob: util/promise/promise.go
| 1 | package promise |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "sync" |
| 6 | ) |
| 7 | |
| 8 | // All provides similar concurrency to JavaScript's Promise.All, however with 1 distinction. []func that |
| 9 | // are passed in must respect fnCtx cancellation and returns, otherwise All will block even if fnCtx is cancelled. |
| 10 | func All[V comparable](fnCtx context.Context, fns ...func(fnCtx context.Context) (V, error)) ([]V, []error) { |
| 11 | var ( |
| 12 | wg = sync.WaitGroup{} |
| 13 | results = make([]V, len(fns)) |
| 14 | errors = make([]error, len(fns)) |
| 15 | done = make(chan struct{}, 1) |
| 16 | ) |
| 17 | wg.Add(len(fns)) |
| 18 | go func() { |
| 19 | wg.Wait() |
| 20 | close(done) |
| 21 | }() |
| 22 | for i, fn := range fns { |
| 23 | go func(i int, fn func(context.Context) (V, error)) { |
| 24 | defer wg.Done() |
| 25 | v, e := fn(fnCtx) |
| 26 | if e != nil { |
| 27 | errors[i] = e |
| 28 | return |
| 29 | } |
| 30 | results[i] = v |
| 31 | }(i, fn) |
| 32 | } |
| 33 | select { |
| 34 | case <-done: |
| 35 | case <-fnCtx.Done(): |
| 36 | // assert that the fn returns first |
| 37 | <-done |
| 38 | } |
| 39 | return results, errors |
| 40 | } |