Skip to content

Commit 3ce29b6

Browse files
committed
doc: update readme.
1 parent 058ead2 commit 3ce29b6

File tree

1 file changed

+91
-32
lines changed

1 file changed

+91
-32
lines changed

README.md

Lines changed: 91 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,76 +7,135 @@
77
![License Badge](https://img.shields.io/github/license/ghosind/go-async)
88
[![Go Reference](https://pkg.go.dev/badge/github.com/ghosind/go-async.svg)](https://pkg.go.dev/github.com/ghosind/go-async)
99

10-
A tool collection that provided asynchronous workflow control utilities, inspired by `Promise` in the Javascript.
10+
A tool collection that provided asynchronous workflow control utilities, inspired by [JavaScript `Promise` Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) and [Node.js async package](https://caolan.github.io/async/v3/).
1111

12-
## Installation
12+
## Installation and Requirement
13+
14+
Run the following command to install the library, and this library requires Go 1.18 and later versions.
1315

1416
```sh
1517
go get -u github.com/ghosind/go-async
1618
```
1719

1820
## Getting Started
1921

20-
We provided the `All` function to execute all the functions asynchronously. It'll return `-1` and a nil error if all functions are completed and no error return or panic. If some function returns an error or panic, it'll immediately return the index of the function and the error and send the cancel signal to all other functions.
22+
### The function to run
23+
24+
The most of utility functions of this library accept any type of function to run, you can set the parameters and the return values as any type and any number of return values that you want. However, for best practice, we recommend you to set the first parameter as `context.Context` to receive the signals and make the type of the last return value as an error to let the utilities know whether an error happened or not.
25+
26+
### Run all functions until they are finished
27+
28+
`All` function can help you to execute all the functions asynchronously. It'll wrap all return values to a two-dimensional `any` type slice and return it if all functions are completed and no error returns or panic.
29+
30+
If any function returns an error or panics, the `All` function will terminate immediately and return the error. It'll also send a cancel signal to other uncompleted functions by context if they accept a context by their first parameter.
2131

2232
```go
23-
index, err := async.All(func (ctx context.Context) error) {
24-
return nil
25-
}, func (ctx context.Context) error) {
26-
return nil
33+
out, err := async.All(func (ctx context.Context) (int, error)) {
34+
return 0, nil
35+
}, func (ctx context.Context) (string, error)) {
36+
return "hello", nil
2737
}/*, ...*/)
28-
// index: -1
38+
// out: [][]any{{0, nil}, {"hello", nil}}
2939
// err: <nil>
3040

31-
index, err := async.All(func (ctx context.Context) error) {
32-
return nil
33-
}, func (ctx context.Context) error) {
34-
return errors.New("some error")
41+
out, err := async.All(func (ctx context.Context) (int, error)) {
42+
return 0, nil
43+
}, func (ctx context.Context) (string, error)) {
44+
return "", errors.New("some error")
3545
}/*, ...*/)
36-
// index: 1
37-
// err: Some error
46+
// out: nil
47+
// err: some error
3848
```
3949

40-
If you do not want to terminate the execution of other functions if some function returns an error or panic, you can try the `AllCompleted` function. The `AllCompleted` function will return until all functions are finished or panic. It'll return a list of the function return values (error), and a boolean value to indicate any functions return error or panic.
50+
If you do not want to terminate the execution when some function returns an error or panic, you can try the `AllCompleted` function. The `AllCompleted` function executes until all functions are finished or panic. It'll return a list of the function return values, and an error to indicate whether any functions return error or panic.
4151

4252
```go
43-
errors, ok := async.All(func (ctx context.Context) error) {
44-
return nil
45-
}, func (ctx context.Context) error) {
46-
return errors.New("some error")
53+
out, err := async.All(func (ctx context.Context) (int, error) {
54+
return 0, nil
55+
}, func (ctx context.Context) (string, error) {
56+
return "", errors.New("some error")
4757
}/*, ...*/)
48-
// errors: [<nil>, some error]
49-
// ok: false
58+
// out: [][]any{{0, nil}, {"", some error}}}
59+
// err: function 1 error: some error
5060
```
5161

52-
We also provided the `Race` function, it will return when a function returns or panics, and does not terminate other functions.
62+
### Get first output
63+
64+
If you want to run a list of functions and get the output of the first finish function, you can try the `Race` function. The `Race` function will run all functions asynchronously, and return when a function is finished or panicked.
65+
66+
The `Race` function returns three values:
67+
68+
- 1st value: an output list of the first finish function.
69+
- 2nd value: the index of the first finish function.
70+
- 3rd value: the execution error that from the first finish or panic function.
5371

5472
```go
55-
index, err := async.Race(func (ctx context.Context) error {
73+
out, index, err := async.Race(func (ctx context.Context) (int, error) {
5674
request.Get("https://example.com")
57-
return nil
58-
}, func (ctx context.Context) error {
75+
return 0, nil
76+
}, func (ctx context.Context) (string, error) {
5977
time.Sleep(time.Second)
60-
return nil
78+
return "test", nil
6179
})
62-
// index = 0 if the request is finished within one second.
63-
// index = 1 if the request is finished after one second.
80+
// If the first function faster than the second one:
81+
// out: []any{0, nil}, index: 0, err: nil
82+
//
83+
// Otherwise:
84+
// out: []any{"test", nil}, index: 1, err: nil
6485
```
6586

87+
### Run all functions with concurrency limit
88+
6689
To run all functions asynchronously but with the specified concurrency limitation, you can use the `Parallel` function. The `Parallel` function accepts a number that the concurrency limitation and the list of functions to run. The number of the concurrency limitation must be greater than or equal to 0, and it has the same effect as the `All` function if the number is 0.
6790

6891
```go
6992
// Run 2 functions asynchronously at the time.
70-
async.Parallel(2, func (ctx context.Context) error {
93+
out, err := async.Parallel(2, func (ctx context.Context) (int, error) {
7194
// Do something
72-
return nil
73-
}, func (ctx context.Context) error {
95+
return 1, nil
96+
}, func (ctx context.Context) (string, error) {
7497
// Do something
75-
return nil
98+
return "hello", nil
7699
}, func (ctx context.Context) error {
77100
// Do something
78101
return nil
79102
}/* , ... */)
103+
// out: [][]any{{1, nil}, {"hello", nil}, {nil}}
104+
// err: nil
80105
```
81106

82107
The `Parallel` will also be terminated if any function panics or returns an error. If you do not want to terminate the execution of other functions, you can try to use `ParallelCompleted`. The `ParallelCompleted` function will run all functions until all functions are finished. It will return the errors list and a boolean value to indicate whether any function errored.
108+
109+
### Run a function forever until it returns an error or panic
110+
111+
For `Forever` function, you can use it to run a function forever until it returns an error or panics. You need to run the `Forever` function with a `ForeverFn` type function, and you can see more information about `ForeverFn` after the following example.
112+
113+
```go
114+
err := async.Forever(func(ctx context.Context, next func(context.Context)) error {
115+
v, ok := ctx.Value("key")
116+
if ok {
117+
vi := v.(int)
118+
if vi == 5 {
119+
return errors.New("finish")
120+
}
121+
122+
fmt.Printf("value: %d\n", vi)
123+
124+
next(context.WithValue(ctx, "key", vi + 1))
125+
} else {
126+
next(context.WithValue(ctx, "key", 1))
127+
}
128+
})
129+
fmt.Printf("err: %v\n", err)
130+
// value: 1
131+
// value: 2
132+
// value: 3
133+
// value: 4
134+
// err: finish
135+
```
136+
137+
The `ForeverFn` accepts two parameters, the first one is a context from the caller or the last invocation. The second parameter of `ForeverFn` is a function to set the context that passes to the next invocation. For `ForeverFn`, it is an optional behavior to call the `next` function, and only the first invoke will work.
138+
139+
### Customize context
140+
141+
For all utility functions, you can use the `XXXWithContext` function (like `AllWithContext`, `RaceWithContext`, ...) to set the context by yourself.

0 commit comments

Comments
 (0)