1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-06 21:52:28 +08:00

feat: add promise All, Race, Any methods

This commit is contained in:
dudaodong
2023-03-16 15:34:28 +08:00
parent 5ab322ade2
commit c799d10ce9

View File

@@ -1,7 +1,7 @@
// Copyright 2023 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package async contain some features to support async programming. eg, promise, asycn/await, eventbus.
// Package async contain some featurese to support async programming. eg, promise, asycn/await, eventbus.
package async
import (
@@ -11,6 +11,7 @@ import (
)
// Promise represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
// ref : chebyrash/promise (https://github.com/chebyrash/promise)
// see js promise: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
type Promise[T any] struct {
runnable func(resolve func(T), reject func(error))
@@ -35,12 +36,6 @@ func New[T any](runnable func(resolve func(T), reject func(error))) *Promise[T]
wg: &sync.WaitGroup{},
}
// p.wg.Add(1)
// go func() {
// defer p.handlePanic()
// runnable(p.resolve, p.reject)
// }()
defer p.run()
return p
@@ -113,7 +108,7 @@ func (p *Promise[T]) reject(err error) {
}
// Then allows chain calls to other promise methods.
func Then[T1, T2 any](promise Promise[T1], resolve1 func(value T1) T2) *Promise[T2] {
func Then[T1, T2 any](promise *Promise[T1], resolve1 func(value T1) T2) *Promise[T2] {
return New(func(resolve2 func(T2), reject func(error)) {
result, err := promise.Await()
if err != nil {
@@ -165,3 +160,116 @@ func (p *Promise[T]) Await() (T, error) {
p.wg.Wait()
return p.result, p.err
}
type tuple[T1, T2 any] struct {
_1 T1
_2 T2
}
// All resolves when all of the promises have resolved, reject immediately upon any of the input promises rejecting.
func All[T any](promises []*Promise[T]) *Promise[[]T] {
if len(promises) == 0 {
return nil
}
return New(func(resolve func([]T), reject func(error)) {
valsChan := make(chan tuple[T, int], len(promises))
errsChan := make(chan error, 1)
for idx, p := range promises {
idx := idx
_ = Then(p, func(data T) T {
valsChan <- tuple[T, int]{_1: data, _2: idx}
return data
})
_ = Catch(p, func(err error) error {
errsChan <- err
return err
})
}
resolutions := make([]T, len(promises))
for idx := 0; idx < len(promises); idx++ {
select {
case val := <-valsChan:
resolutions[val._2] = val._1
case err := <-errsChan:
reject(err)
return
}
}
resolve(resolutions)
})
}
// Race will settle the first fullfiled promise among muti promises.
func Race[T any](promises []*Promise[T]) *Promise[T] {
if len(promises) == 0 {
return nil
}
return New(func(resolve func(T), reject func(error)) {
valsChan := make(chan T, 1)
errsChan := make(chan error, 1)
for _, p := range promises {
_ = Then(p, func(data T) T {
valsChan <- data
return data
})
_ = Catch(p, func(err error) error {
errsChan <- err
return err
})
}
select {
case val := <-valsChan:
resolve(val)
case err := <-errsChan:
reject(err)
}
})
}
// Any resolves as soon as any of the input's Promises resolve, with the value of the resolved Promise.
// Any rejects if all of the given Promises are rejected with a combination of all errors.
func Any[T any](promises ...*Promise[T]) *Promise[T] {
if len(promises) == 0 {
return nil
}
return New(func(resolve func(T), reject func(error)) {
valsChan := make(chan T, 1)
errsChan := make(chan tuple[error, int], len(promises))
for idx, p := range promises {
idx := idx
_ = Then(p, func(data T) T {
valsChan <- data
return data
})
_ = Catch(p, func(err error) error {
errsChan <- tuple[error, int]{_1: err, _2: idx}
return err
})
}
errs := make([]error, len(promises))
for idx := 0; idx < len(promises); idx++ {
select {
case val := <-valsChan:
resolve(val)
return
case err := <-errsChan:
errs[err._2] = err._1
}
}
errCombo := errs[0]
// for _, err := range errs[1:] {
// errCombo = errors.
// }
reject(errCombo)
})
}