untech2-async is a promise-like library built for Go, technically inspired by the fully-featured JavaScript promise library bluebird.js. It is designed for JavaScript/TypeScript developers who are new to Go. The name is taken from the President of Indonesia's jargon, "Hey, Antek-antek asing!", which sounds similar to "Hey, untech-untech async!" to non-native Indonesian speakers.
Unlike politician' promise, for example, the Indonesia Vice President's pledge during his political campaign to create 19 million jobs commitments, where it can be hard to track. A promise in untech-async is far more reliable. It is guaranteed to be settled, resolving to one of three states: fulfilled, rejected, or cancelled. No ambiguity, just results.
go get github.com/ivanj26/untech-asyncpackage main
import (
"context"
"fmt"
"time"
"github.com/ivanj26/untech-async"
)
func main() {
p := untech_async.NewPromise(context.Background(), func(resolve untech_async.ResolveCallback[string], reject untech_async.RejectCallback) {
fmt.Println("Doing some async work...")
time.Sleep(1 * time.Second)
resolve("Hello from Promise!")
})
fmt.Println("Waiting for promise to complete...")
// Await blocks until the promise is fulfilled or rejected.
result, err := p.Await()
if err != nil {
fmt.Printf("Promise rejected with error: %v\n", err)
return
}
fmt.Printf("Promise fulfilled with result: %s\n", result)
}The .Then() method allows you to execute asynchronous operations in sequence. It takes the result of the previous promise, processes it, and returns a new promise with the new result.
package main
import (
"context"
"fmt"
"strings"
"time"
"github.com/ivanj26/untech-async"
)
func main() {
p := untech_async.NewPromise(context.Background(), func(resolve untech_async.ResolveCallback[string], reject untech_async.RejectCallback) {
time.Sleep(500 * time.Millisecond)
resolve("hello world")
})
// Chain operations using .Then()
p2 := p.
Then(func(value string) (string, error) {
fmt.Printf("First 'Then' received: %s\n", value)
return strings.ToUpper(value), nil
}).
Then(func(value string) (string, error) {
fmt.Printf("Second 'Then' received: %s\n", value)
return "Processed: " + value, nil
})
result, err := p2.Await()
if err != nil {
fmt.Printf("Chained promise rejected: %v\n", err)
return
}
fmt.Printf("Final result: %s\n", result)
}If any promise in a chain is rejected, it will jump to the next .Catch() block. You can use Catch to handle errors, recover from them, and continue the chain with a new value.
package main
import (
"context"
"errors"
"fmt"
"time"
"github.com/ivanj26/untech-async"
)
func main() {
p := untech_async.NewPromise(context.Background(), func(resolve untech_async.ResolveCallback[string], reject untech_async.RejectCallback) {
time.Sleep(500 * time.Millisecond)
reject(errors.New("something went wrong"))
})
// Use .Catch() to recover from the error and provide a default value.
pRecover := p.Catch(func(ctx context.Context, err error) (string, error) {
fmt.Printf("Caught error: %v\n", err)
return "recovered value", nil
})
result, err := pRecover.Await()
if err != nil {
fmt.Printf("This should not happen, but got error: %v\n", err)
} else {
fmt.Printf("Final result after recovery: %s\n", result)
}
}Promises are integrated with Go's context package. You can cancel promises through context timeouts, deadlines, or manual cancellation.
package main
import (
"context"
"errors"
"fmt"
"time"
"github.com/ivanj26/untech-async"
)
func main() {
// To set a timeout for your Promise object, call context.Timeout(), and pass it to Promise constructor.
// Once timeout exceeded, it will response an error.
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer cancel()
p := untech_async.NewPromise(ctx, func(resolve untech_async.ResolveCallback[string], reject untech_async.RejectCallback) {
fmt.Println("Starting a long-running task (1 second)...")
time.Sleep(1 * time.Second)
resolve("done")
})
_, err := p.Await()
if err != nil {
fmt.Printf("Promise failed: %v\n", err) // Promise failed: context deadline exceeded
}
// Manual Cancellation Example
p2 := untech_async.NewPromise(context.Background(), func(resolve untech_async.ResolveCallback[string], reject untech_async.RejectCallback) {
time.Sleep(1 * time.Second)
resolve("done")
})
go func() {
time.Sleep(500 * time.Millisecond)
p2.Cancel()
}()
_, err2 := p2.Await()
if err2 != nil {
fmt.Printf("Promise 2 failed: %v\n", err2) // Promise 2 failed: context canceled
}
}untech-async provides utility functions to work with multiple promises at once.
All returns a promise that fulfills when all input promises have fulfilled. If any promise rejects, All immediately rejects.
p1 := untech_async.NewPromise(ctx, func(r untech_async.ResolveCallback[string], _ untech_async.RejectCallback) { r("one") })
p2 := untech_async.NewPromise(ctx, func(r untech_async.ResolveCallback[string], _ untech_async.RejectCallback) { r("two") })
all := untech_async.All(ctx, p1, p2)
results, _ := all.Await() // results is []string{"one", "two"}Race returns a promise that settles as soon as the first input promise settles.
pSlow := untech_async.NewPromise(ctx, func(r untech_async.ResolveCallback[string], _ untech_async.RejectCallback) { time.Sleep(100*time.Millisecond); r("slow") })
pFast := untech_async.NewPromise(ctx, func(r untech_async.ResolveCallback[string], _ untech_async.RejectCallback) { time.Sleep(10*time.Millisecond); r("fast") })
race := untech_async.Race(ctx, pSlow, pFast)
result, _ := race.Await() // result is "fast"AllSettled returns a promise that fulfills after all input promises have settled. It provides a slice of SettledResult structs describing the outcome of each promise.
p1 := untech_async.NewPromise(ctx, func(r untech_async.ResolveCallback[int], _ untech_async.RejectCallback) { r(1) })
p2 := untech_async.NewPromise(ctx, func(_ untech_async.ResolveCallback[int], r untech_async.RejectCallback) { r(errors.New("failure")) })
allSettled := untech_async.AllSettled(ctx, []*untech_async.Promise[int]{p1, p2})
results, _ := allSettled.Await()
// results[0] = {Value: 1, Err: nil}
// results[1] = {Value: 0, Err: "failure"}The library also includes other powerful utilities for processing collections:
Map(items, mapFn, opts): Processes a slice of items concurrently with a configurable concurrency limit.Some(promises, count): Fulfills whencountpromises have fulfilled.Filter(promises, filterFn): Filters promise results based on a predicate.Reduce(promises, reduceFn, initial): Reduces promise results in order.ReduceParallel(promises, reduceFn, initial): Reduces promise results as they complete.
Check the util_test.go file for detailed examples of their usage.
Contributions are welcome.
See PULL_REQUEST_TEMPLATE.md.
MIT License