为什么下面的代码中出现死锁?我正在尝试从goroutine向外部返回一些内容
package main
import (
"fmt"
"syscall/js"
"time"
)
func test(this js.Value, i []js.Value) interface{} {
done := make(chan string, 1)
go func() {
doRequest := func(this js.Value, i []js.Value) interface{} {
time.Sleep(time.Second)
return 0
}
js.Global().Set("doRequest", js.FuncOf(doRequest))
args := []js.Value{js.ValueOf("url")}
var x js.Value
doRequest(x, args)
done <- "true"
}()
aa := <-done
fmt.Println(aa)
return 0
}
func main() {
c := make(chan bool)
js.Global().Set("test", js.FuncOf(test))
<-c
}
当我在浏览器上运行并调用test()时,将显示以下错误
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
.....
func main() {
c := make(chan bool)
js.Global().Set("test", js.FuncOf(test))
<-c
}
您已创建通道c
,然后等待从中接收值。注意c
是main
函数局部变量的方式。对c
的引用永远不会在程序的其他任何地方传递,因此c
通道上永远不会发送任何值,因此您的主goroutine将永远等待接收。
几乎是错误消息中所说的。所有goroutine都在睡觉。 main
不会启动任何东西,只接收一个通道,因此它被阻塞,并且没有其他goroutine正在运行,因此main
不可能再次唤醒,因此运行时会出现紧急情况。
[如果我没记错的话,不像普通的Go,GopherJS不会关闭所有内容并在main
退出时退出(部分原因是:那到底意味着什么?与Go程序最接近的类比是关闭网页!太烂了,所以GopherJS不会那样做。因此,严格来说,在GopherJS中,您不必为使main
保持活动状态而进行的操作。
就是说,如果您在最后说(例如)time.Sleep(time.Hour)
,则在所有goroutine仍处于睡眠状态(严格来说)时,main
最终会唤醒,运行时知道,所以它不会在这种情况下恐慌。
关于实际的test
功能,一旦尝试使用它,就会收到相关的错误消息:Uncaught Error: runtime error: cannot block in JavaScript callback, fix by wrapping code in goroutine
。 test
在通道上进行了阻塞调用,而GopherJS不允许在直接从Javascript调用的函数中进行此操作,因此会感到恐慌。 (当我在playground中运行它时,我也得到了Uncaught TypeError: r is not a function
,但这只是先前错误的结果。)我think您要尝试做的是等待doRequest
完成,打印值并返回,但是那行不通。为此,您需要使用本机Javascript Promise或其他异步机制。