Coder Social home page Coder Social logo

go-promise's Introduction

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).

go-promise's People

Contributors

fanliao avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-promise's Issues

Return channel on promise.Resolve

I think it would be great being able to wait for Resolve method to actually run its callbacks, or at least to have two methods like Resolve and ResolveAsync.

I'd expect the following code to print "running callback" but this doesn't happen since promise.Resolve is using a go routine and this is not clear.

package main

import "github.com/fanliao/go-promise"
import "fmt"

func main() {
        p := promise.NewPromise()
        p.OnSuccess(func(v interface{}) {
                fmt.Println("running callback")
        })
        p.Resolve(nil)
}

Thank you!

how to pass params to task?

task := func(param interface{} //=========== here, task with some param
)(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

}

// when start an promise how to pass param for task?
f := promise.Start(task).OnSuccess(func(v interface{}) {
}

futrue spell mistake

In project subtiltle

A library implement futrue and promise

Should be

A library implement future and promise

all goroutines are asleep - deadlock

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

    f,ok := promise.Start(task1).Pipe(task2)
    if ok {
        r, err := f.Get()   //return 20
        fmt.Println(r,err)
    }

}
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
github.com/fanliao/go-promise.(*Future).Get(0xc0420b8980, 0xc042083f38, 0x1, 0x1, 0xc0420b8980)
	D:/Code/golang/src/github.com/fanliao/go-promise/future.go:138 +0x4f
main.PromisePipelining1()
	D:/Code/golang/src/studygo/futrue/future.go:148 +0xd4
main.main()
	D:/Code/golang/src/studygo/futrue/future.go:16 +0x27
exit status 2

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.