Skip to content
/ promise Public

Fast, lightweight, and lock-free promises for Go... the Go way. Providing an efficient and idiomatic way for creating asynchronous pipelines in Go.

License

Notifications You must be signed in to change notification settings

asmsh/promise

Repository files navigation

Promise PkgGoDev Go Report Card GoCoverIO Tests

Fast, lightweight, and lock-free promises for Go... the Go way

Features

  • Fast and low memory overhead implementation
  • Lock-free implementation
  • Extensible implementation that can be used to provide typed promises
  • Automatic panic recovering
  • An API that focuses on Go's idioms, like:
    • Multi return parameters
    • Error being a value
    • The convention of returning errors as the last return parameter
    • The existence of panics and their difference from errors.

Overview

What's a Promise ?

A Promise represents some asynchronous work. It offers ways to get the eventual result of that asynchronous work.
Read more on its Wiki page.

Why in Go ?

Waiting for a goroutine, or returning result from a goroutine, specially with multi return parameters, can get tedious, as it usually requires using more than one variable(a channel with a struct type whose fields correspond to the return parameters, or a sync.WaitGroup with some variables).

But using a promise, it's now possible to wait for the corresponding goroutine to finish and/or access the returned result from it, along with other features, like knowing the status of that goroutine, building computation pipelines, and recovering from panics.

Installation

go get github.com/asmsh/promise

Note: some breaking changes maybe present between each minor version, until the release of v1.0.0, so always check the changelog before updating.

Prerequisites

Go 1.13+

Usage

Basic Usage:

  • If you want to return some values from a goroutine:
p := promise.GoRes(func () promise.Res {
	/* do some work, asynchronously */
	return promise.Res{"go", "golang"} // return any values(as elements)
})
  • If you don't want to return any values:
p := promise.Go(func () {
	/* do some work, asynchronously */
})

Then use any of p's methods to wait for it, access its result, or create a pipeline.

Examples

  • The simplest use case, is to use it as a sync.WaitGroup with only one task:
package main

import "github.com/asmsh/promise"

func main() {
	p := promise.Go(func() {
		/* do some work, asynchronously */
	})

	/* do some other work */

	p.Wait() // wait for the async work to finish

	/* do some other work */
}

The following code is equivalent to the previous, but using only the standard library:

package main

import "sync"

func main() {
	wg := &sync.WaitGroup{}
	wg.Add(1)
	go func(wg *sync.WaitGroup) {
		/* do some work, asynchronously */
		wg.Done()
	}(wg)

	/* do some other work */

	wg.Wait() // wait for the async work to finish

	/* do some other work */
}
  • A typical use case, is to use it to return some result from a goroutine:
package main

import (
	"net/http"

	"github.com/asmsh/promise"
)

func main() {
	p := promise.GoRes(func() promise.Res {
		resp, err := http.Get("https://golang.org/")
		return promise.Res{resp, err}
	}).Then(func(res promise.Res, ok bool) promise.Res {
		// uncomment the following and do something with resp..
		//resp := res[0].(*http.Response)
		return nil
	}).Catch(func(err error, res promise.Res, ok bool) promise.Res {
		// handle the error..
		return nil
	})

	/* do some other work */

	p.Wait() // wait for all the work to finish

	/* do some other work */
}
  • It can be embedded or extended, to provide typed promises, like the asyncHttp, or the ctxProm examples.

  • It provides JavaScript-like Resolver constructor, which can be used like in this example.