diff --git a/README.md b/README.md index 6c1bafa..ee7c0f8 100644 --- a/README.md +++ b/README.md @@ -1254,6 +1254,22 @@ ch := lo.Async(func() lo.Tuple2[int, error] { // chan lo.Tuple2[int, error] ({42, nil}) ``` +### Async{0->1} + +Executes a function in a goroutine and returns the result in a channel. +For function without return, the channel will be closed once the function finishes. + +```go +ch := lo.Async0(func() { time.Sleep(10 * time.Second) }) +// chan struct{} + +ch := lo.Async1(func() int { + time.Sleep(10 * time.Second); + return 42 +}) +// chan int (42) +``` + ### Must Wraps a function call to panics if second argument is `error` or `false`, returns the value otherwise. diff --git a/concurrency.go b/concurrency.go index d0d3845..bc4fa83 100644 --- a/concurrency.go +++ b/concurrency.go @@ -8,3 +8,18 @@ func Async[T any](f func() T) chan T { }() return ch } + +// Async0 executes a function in a goroutine and returns a channel closed after execution. +func Async0(f func()) chan struct{} { + ch := make(chan struct{}) + go func() { + f() + close(ch) + }() + return ch +} + +// Async1 executes a function in a goroutine and returns the result in a channel. +func Async1[A any](f func() A) chan A { + return Async(f) +} diff --git a/concurrency_test.go b/concurrency_test.go index 03317e3..c552a5b 100644 --- a/concurrency_test.go +++ b/concurrency_test.go @@ -26,3 +26,41 @@ func TestAsync(t *testing.T) { is.Fail("Async should not block") } } + +func TestAsyncX(t *testing.T) { + is := assert.New(t) + + { + sync := make(chan struct{}) + + ch := Async0(func() { + <-sync + }) + + sync <- struct{}{} + + select { + case <-ch: + case <-time.After(time.Millisecond): + is.Fail("Async0 should not block") + } + } + + { + sync := make(chan struct{}) + + ch := Async1(func() int { + <-sync + return 10 + }) + + sync <- struct{}{} + + select { + case result := <-ch: + is.Equal(result, 10) + case <-time.After(time.Millisecond): + is.Fail("Async1 should not block") + } + } +}