promise

package module
v0.0.0-...-f72f74c Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 19, 2020 License: MIT Imports: 9 Imported by: 0

README

go-promise is a Go promise and future library.

Inspired by Futures and promises

Installation

$ go get github.com/fanliao/go-promise

Features

  • Future and Promise

    • NewPromise()
    • promise.Future
  • Promise and Future callbacks

    • .OnSuccess(v interface{})
    • .OnFailure(v interface{})
    • .OnComplete(v interface{})
    • .OnCancel()
  • Get the result of future

    • .Get()
    • .GetOrTimeout()
    • .GetChan()
  • Set timeout for future

    • .SetTimeout(ms)
  • Merge multiple promises

    • WhenAll(func1, func2, func3, ...)
    • WhenAny(func1, func2, func3, ...)
    • WhenAnyMatched(func1, func2, func3, ...)
  • Pipe

    • .Pipe(funcWithDone, funcWithFail)
  • Cancel the future

    • .Cancel()
    • .IsCancelled()
  • Create future by function

    • Start(func() (r interface{}, e error))
    • Start(func())
    • Start(func(canceller Canceller) (r interface{}, e error))
    • Start(func(canceller Canceller))
  • Immediate wrappers

    • Wrap(interface{})
  • Chain API

    • Start(taskDone).Done(done1).Fail(fail1).Always(alwaysForDone1).Pipe(f1, f2).Done(done2)

Quick start

Promise and Future

import "github.com/fanliao/go-promise"
import "net/http"

p := promise.NewPromise()
p.OnSuccess(func(v interface{}) {
   ...
}).OnFailure(func(v interface{}) {
   ...
}).OnComplete(func(v interface{}) {
   ...
})

go func(){
	url := "http://example.com/"
	
	resp, err := http.Get(url)
	defer resp.Body.Close()
	if err != nil {
		p.Reject(err)
	}
	
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		p.Reject(err)
	}
	p.Resolve(body)
}()
r, err := p.Get()

If you want to provide a read-only view, you can get a future variable:

p.Future //cannot Resolve, Reject for a future

Can use Start function to submit a future task, it will return a future variable, so cannot Resolve or Reject the future outside of Start function:

import "github.com/fanliao/go-promise"
import "net/http"

task := func()(r interface{}, err error){
	url := "http://example.com/"
	
	resp, err := http.Get(url)
	defer resp.Body.Close()
	if err != nil {
		return nil, err
	}
	
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	return body, nil
}

f := promise.Start(task).OnSuccess(func(v interface{}) {
   ...
}).OnFailure(func(v interface{}) {
   ...
}).OnComplete(func(v interface{}) {
   ...
})
r, err := f.Get()

Get the result of future

Please note the process will be block until the future task is completed

f := promise.Start(func() (r interface{}, err error) {
	return "ok", nil  
})
r, err := f.Get()  //return "ok", nil

f := promise.Start(func() (r interface{}, err error) {
	return nil, errors.New("fail")  
})
r, err := f.Get()  //return nil, errorString{"fail"}

Can wait until timeout

f := promise.Start(func() (r interface{}, err error) {
	time.Sleep(500 * time.Millisecond)
	return "ok", nil 
})
r, err, timeout := f.GetOrTimeout(100)  //return nil, nil, true

Merge multiple futures

Creates a future that will be completed when all of the supplied future are completed.

task1 := func() (r interface{}, err error) {
	return "ok1", nil
}
task2 := func() (r interface{}, err error) {
	return "ok2", nil
}

f := promise.WhenAll(task1, task2)
r, err := f.Get()    //return []interface{}{"ok1", "ok2"}

If any future is failure, the future returnd by WhenAll will be failure

task1 := func() (r interface{}, err error)  {
	return "ok", nil
}
task2 := func() (r interface{}, err error)  {
	return nil, errors.New("fail2")
}
f := promise.WhenAll(task1, task2)
r, ok := f.Get()    //return nil, *AggregateError

Creates a future that will be completed when any of the supplied tasks is completed.

task1 := func() (r interface{}, err error) {
	return "ok1", nil
}
task2 := func() (r interface{}, err error) {
	time.Sleep(200 * time.Millisecond)
	return nil, errors.New("fail2")
}

f := promise.WhenAny(task1, task2)
r, err := f.Get()  //return "ok1", nil

Also can add a predicate function by WhenAnyMatched, the future that will be completed when any of the supplied tasks is completed and match the predicate.

task1 := func() (r interface{}, err error) {
	time.Sleep(200 * time.Millisecond)
	return "ok1", nil
}
task2 := func() (r interface{}, err error) {
	return "ok2", nil
}

f := promise.WhenAnyMatched(func(v interface{}) bool{
	return v == "ok1"
}, task1, task2)
r, err := f.Get()  //return "ok1", nil

Promise pipelining

task1 := func() (r interface{}, err error) {
	return 10, nil
}
task2 := func(v interface{}) (r interface{}, err error) {
	return v.(int) * 2, nil
}

f := promise.Start(task1).Pipe(task2)
r, err := f.Get()   //return 20

Cancel the future or set timeout

If need cancel a future, can pass a canceller object to task function

import "github.com/fanliao/go-promise"
import "net/http"

p := promise.NewPromise().EnableCanceller()

go func(canceller promise.Canceller){
	for i < 50 {
		if canceller.IsCancelled() {
			return
		}
		time.Sleep(100 * time.Millisecond)
	}
}(p.Canceller())
f.Cancel()

r, err := p.Get()   //return nil, promise.CANCELLED
fmt.Println(p.Future.IsCancelled())      //true

Or can use Start to submit a future task which can be cancelled

task := func(canceller promise.Canceller) (r interface{}, err error) {
	for i < 50 {
		if canceller.IsCancelled() {
			return 0, nil
		}
		time.Sleep(100 * time.Millisecond)
	}
	return 1, nil
}
f := promise.Start(task1)
f.Cancel()

r, err := f.Get()   //return nil, promise.CANCELLED
fmt.Println(f.IsCancelled())      //true

When call WhenAny() function, if a future is completed correctly, then will try to check if other futures enable cancel. If yes, will request cancelling all other futures.

You can also set timeout for a future

task := func(canceller promise.Canceller) (r interface{}, err error) {
	time.Sleep(300 * time.Millisecond)
	if !canceller.IsCancelled(){
		fmt.Println("Run done")
	} 
	return
}

f := promise.Start(task).OnCancel(func() {
	fmt.Println("Future is cancelled")
}).SetTimeout(100)

r, err := f.Get() //return nil, promise.CANCELLED
fmt.Println(f.IsCancelled()) //print true

Document

License

go-promise is licensed under the MIT Licence, (http://www.apache.org/licenses/LICENSE-2.0.html).

Documentation

Overview

Package promise provides a complete promise and future implementation. A quick start sample:

fu := Start(func()(resp interface{}, err error){
    resp, err = http.Get("http://example.com/")
    return
})

//do somthing... resp, err := fu.Get()

Index

Constants

View Source
const (
	CALLBACK_DONE callbackType = iota
	CALLBACK_FAIL
	CALLBACK_ALWAYS
	CALLBACK_CANCEL
)
View Source
const (
	RESULT_SUCCESS resultType = iota
	RESULT_FAILURE
	RESULT_CANCELLED
)

Variables

View Source
var (
	CANCELLED error = &CancelledError{}
)

Functions

This section is empty.

Types

type AggregateError

type AggregateError struct {
	InnerErrs []error
	// contains filtered or unexported fields
}

AggregateError aggregate multi errors into an error

func (*AggregateError) Error

func (e *AggregateError) Error() string

type CancelledError

type CancelledError struct {
}

CancelledError present the Future object is cancelled.

func (*CancelledError) Error

func (e *CancelledError) Error() string

type Canceller

type Canceller interface {
	IsCancelled() bool
	Cancel()
}

Canceller is used to check if the future is cancelled It usually be passed to the future task function for future task function can check if the future is cancelled.

type Future

type Future struct {
	Id int //Id can be used as identity of Future
	// contains filtered or unexported fields
}

Future provides a read-only view of promise, the value is set by using Resolve, Reject and Cancel methods of related Promise

func Start

func Start(act interface{}, syncs ...bool) *Future

Start start a goroutines to execute task function and return a Future that presents the result. If option paramter is true, the act function will be sync called. Type of act can be any of below four types:

func() (r interface{}, err error):
   if err returned by act != nil or panic error, then Future will be rejected with error,
   otherwise be resolved with r.
func():
   if act panic error, then Future will be rejected, otherwise be resolved with nil.
func(c promise.Canceller) (r interface{}, err error):
   if err returned by act != nil or panic error,
   then Future will be rejected with err, otherwise be resolved with r.
   We can check c.IsCancelled() to decide whether need to exit act function
func(promise.Canceller):
   if act panic error, then Future will be rejected with error, otherwise be resolved with nil.
   We can check c.IsCancelled() to decide whether need to exit act function.
error:
   Future will be rejected with error immediately
other value:
   Future will be resolved with value immediately

func WhenAll

func WhenAll(acts ...interface{}) (fu *Future)

WhenAll receives function slice and returns a Future. If all Futures are resolved, this Future will be resolved and return results slice. Otherwise will rejected with results slice returned by all Futures Legit types of act are same with Start function

func WhenAny

func WhenAny(acts ...interface{}) *Future

WhenAny returns a Future. If any Future is resolved, this Future will be resolved and return result of resolved Future. Otherwise will rejected with results slice returned by all Futures Legit types of act are same with Start function

func WhenAnyMatched

func WhenAnyMatched(predicate func(interface{}) bool, acts ...interface{}) *Future

WhenAnyMatched returns a Future. If any Future is resolved and match the predicate, this Future will be resolved and return result of resolved Future. If all Futures are cancelled, this Future will be cancelled. Otherwise will rejected with a NoMatchedError included results slice returned by all Futures Legit types of act are same with Start function

func Wrap

func Wrap(value interface{}) *Future

Wrap return a Future that presents the wrapped value

func (*Future) Cancel

func (this *Future) Cancel() (e error)

Cancel sets the status of promise to RESULT_CANCELLED. If promise is cancelled, Get() will return nil and CANCELLED error. All callback functions will be not called if Promise is cancalled.

func (*Future) Canceller

func (this *Future) Canceller() Canceller

Canceller returns a canceller object related to future.

func (*Future) Get

func (this *Future) Get() (val interface{}, err error)

Get will block current goroutines until the Future is resolved/rejected/cancelled. If Future is resolved, value and nil will be returned If Future is rejected, nil and error will be returned. If Future is cancelled, nil and CANCELLED error will be returned.

func (*Future) GetChan

func (this *Future) GetChan() <-chan *PromiseResult

GetChan returns a channel than can be used to receive result of Promise

func (*Future) GetOrTimeout

func (this *Future) GetOrTimeout(mm uint) (val interface{}, err error, timout bool)

GetOrTimeout is similar to Get(), but GetOrTimeout will not block after timeout. If GetOrTimeout returns with a timeout, timeout value will be true in return values. The unit of paramter is millisecond.

func (*Future) IsCancelled

func (this *Future) IsCancelled() bool

IsCancelled returns true if the promise is cancelled, otherwise false

func (*Future) OnCancel

func (this *Future) OnCancel(callback func()) *Future

OnCancel registers a callback function that will be called when Promise is cancelled. If promise is already cancelled, the callback will immediately called.

func (*Future) OnComplete

func (this *Future) OnComplete(callback func(v interface{})) *Future

OnComplete register a callback function that will be called when Promise is rejected or resolved. If promise is already rejected or resolved, the callback will immediately called. According to the status of Promise, value or error will be paramter of Always callback function. Value is the paramter if Promise is resolved, or error is the paramter if Promise is rejected. Always callback will be not called if Promise be called.

func (*Future) OnFailure

func (this *Future) OnFailure(callback func(v interface{})) *Future

OnFailure registers a callback function that will be called when Promise is rejected. If promise is already rejected, the callback will immediately called. The error of Promise will be paramter of Fail callback function.

func (*Future) OnSuccess

func (this *Future) OnSuccess(callback func(v interface{})) *Future

OnSuccess registers a callback function that will be called when Promise is resolved. If promise is already resolved, the callback will immediately called. The value of Promise will be paramter of Done callback function.

func (*Future) Pipe

func (this *Future) Pipe(callbacks ...interface{}) (result *Future, ok bool)

Pipe registers one or two functions that returns a Future, and returns a proxy of pipeline Future. First function will be called when Future is resolved, the returned Future will be as pipeline Future. Secondary function will be called when Futrue is rejected, the returned Future will be as pipeline Future.

func (*Future) SetTimeout

func (this *Future) SetTimeout(mm int) *Future

SetTimeout sets the future task will be cancelled if future is not complete before time out

type NoMatchedError

type NoMatchedError struct {
	Results []interface{}
}

NoMatchedError presents no future that returns matched result in WhenAnyTrue function.

func (*NoMatchedError) Error

func (e *NoMatchedError) Error() string

func (*NoMatchedError) HasError

func (e *NoMatchedError) HasError() bool

type Promise

type Promise struct {
	*Future
}

Promise presents an object that acts as a proxy for a result. that is initially unknown, usually because the computation of its value is yet incomplete (refer to wikipedia). You can use Resolve/Reject/Cancel to set the final result of Promise. Future can return a read-only placeholder view of result.

func NewPromise

func NewPromise() *Promise

NewPromise is factory function for Promise

func (*Promise) Cancel

func (this *Promise) Cancel() (e error)

Cancel sets the status of promise to RESULT_CANCELLED. If promise is cancelled, Get() will return nil and CANCELLED error. All callback functions will be not called if Promise is cancalled.

func (*Promise) OnCancel

func (this *Promise) OnCancel(callback func()) *Promise

OnCancel registers a callback function that will be called when Promise is cancelled. If promise is already cancelled, the callback will immediately called.

func (*Promise) OnComplete

func (this *Promise) OnComplete(callback func(v interface{})) *Promise

OnComplete register a callback function that will be called when Promise is rejected or resolved. If promise is already rejected or resolved, the callback will immediately called. According to the status of Promise, value or error will be paramter of Always callback function. Value is the paramter if Promise is resolved, or error is the paramter if Promise is rejected. Always callback will be not called if Promise be called.

func (*Promise) OnFailure

func (this *Promise) OnFailure(callback func(v interface{})) *Promise

OnFailure registers a callback function that will be called when Promise is rejected. If promise is already rejected, the callback will immediately called. The error of Promise will be paramter of Fail callback function.

func (*Promise) OnSuccess

func (this *Promise) OnSuccess(callback func(v interface{})) *Promise

OnSuccess registers a callback function that will be called when Promise is resolved. If promise is already resolved, the callback will immediately called. The value of Promise will be paramter of Done callback function.

func (*Promise) Reject

func (this *Promise) Reject(err error) (e error)

Resolve sets the error for promise, and the status will be changed to RESULT_FAILURE. if promise is rejected, Get() will return nil and the related error value.

func (*Promise) Resolve

func (this *Promise) Resolve(v interface{}) (e error)

Resolve sets the value for promise, and the status will be changed to RESULT_SUCCESS. if promise is resolved, Get() will return the value and nil error.

type PromiseResult

type PromiseResult struct {
	Result interface{} //result of the Promise
	Typ    resultType  //success, failure, or cancelled?
}

PromiseResult presents the result of a promise. If Typ is RESULT_SUCCESS, Result field will present the returned value of Future task. If Typ is RESULT_FAILURE, Result field will present a related error . If Typ is RESULT_CANCELLED, Result field will be null.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL