我正在尝试在Go中实现Promise,这与Javascript中的类似。
type Promise struct {
Result chan string
Error chan error
}
func NewPromise() (*Promise) {
r := make(chan string, 1)
e := make(chan error, 1)
return &Promise{
Result: r,
Error: e,
}
}
func main() {
var p = NewPromise()
go func(p *Promise) {
time.Sleep(time.Duration(5)*time.Second)
p.Result <- "done"
}(p)
if <- p.Result {
fmt.Println(<-p.Result)
}
// Is it possible to do something else here while wait for 5s?
// Once Promise is fulfilled after 5s, the Result is available.
}
我该怎么做:
Promise
返回主goroutine。Promise.Result
或Promise.Error
不使用通道的不同方法,使其更快/更高效:
type Promise struct {
wg sync.WaitGroup
res string
err error
}
func NewPromise(f func() (string, error)) *Promise {
p := &Promise{}
p.wg.Add(1)
go func() {
p.res, p.err = f()
p.wg.Done()
}()
return p
}
func (p *Promise) Then(r func(string), e func(error)) {
go func() {
p.wg.Wait()
if p.err != nil {
e(p.err)
return
}
r(p.res)
}()
}
"From Events to Futures and Promises and back"(2016年2月出版)上有一篇名为Martin Sulzmann的论文,涵盖了你想要实现的目标。摘要说:
基于渠道通信和期货/承诺的事件是强大的,但对于并发编程而言看似不同的概念。我们表明,一个概念可以用另一个概念表达,但却没有那么费力。我们的结果提供了基于轻量级库的方法来实现事件和期货/承诺。实证结果表明,我们的方法在实践中运作良好。
根据该报纸,期货看起来像这样:
type Comp struct {
value interface{}
ok bool
}
type Future chan Comp
func future(f func() (interface{}, bool)) Future {
future := make(chan Comp)
go func() {
v, o := f()
c := Comp{v, o}
for {
future <- c
}
}()
return future
}
承诺的实施如下:
type Promise struct {
lock chan int
ft Future
full bool
}
func promise() Promise {
return Promise{make(chan int, 1), make(chan Comp), false}
}
func (pr Promise) future() Future {
return pr.ft
}
阅读论文了解详细信息,组合器等。
有很多方法可以做到这一点,但我所做的例如是调整NewPromise()以将一个函数作为一个接受结果和错误通道的arg。然后NewPromise方法使用此函数初始化一个go例程,返回带有相同通道的promise。如果你调用.Then方法,这基本上需要两个函数作为参数。一个将处理您通过结果通道(字符串)的类型和一个处理错误通道的结果类型(错误)的类型。然后.Then方法调用goroutine中的私有.then()方法来选择首先发生的结果,或结果或错误,然后调用适合每个结果的函数。
例如,我只使用了一个简单的自动收报机等待一秒,然后通过结果通道发送“hi”。
我希望这能让你了解一种方法。
GoLang游乐场:https://play.golang.org/p/xc1xvv7hRx
我也在尝试实现javascript的承诺:)。这是一个学习目的项目。在这个实现中,我学习了go的频道,选择,goroutine。我认为这个小型图书馆满足您的需求。
p := New(func(resolve func(interface{}), reject func(error)) {
resolve("sonla")
})
p.Then(func(data interface{}) interface{} {
fmt.Printf("What I get is %v\n", data.(string))
return nil
})
Await(p)
欢迎贡献,如果有人有更好的想法在golang实现承诺。这是我的repo