go之GopherJS 在 goroutine 中的死锁

zhujiabin 阅读:112 2025-06-02 22:19:02 评论:0

为什么下面的代码会出现死锁?我正在尝试将 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]: 
..... 

请您参考如下方法:

几乎就是它在错误消息中所说的内容。所有的 goroutine 都处于休眠状态。 main不启动任何东西,只是接收一个 channel ,所以它被阻塞了,并且没有其他 goroutines 正在运行,所以不可能 main可能会再次唤醒,因此运行时会出现 panic 。

如果我没记错的话,与常规 Go 不同,如果 main,GopherJS 不会关闭所有内容并退出。退出(部分原因是:这到底意味着什么?最接近 Go 程序的模拟是关闭网页!这有点糟糕。所以 GopherJS 不会那样做。)。所以你在做什么来保持main严格来说,在 GopherJS 中,活着不是必需的。

也就是说,如果你说(例如)time.Sleep(time.Hour)最后,当所有的 goroutine 都还在休眠时(严格来说),main最终会唤醒,运行时知道,所以在这种情况下它不会 panic 。

至于你的实际test功能,一旦你尝试了,你会得到一个相关的错误信息:Uncaught Error: runtime error: cannot block in JavaScript callback, fix by wrapping code in goroutine . test在 channel 上进行阻塞调用,而 GopherJS 不允许在直接从 Javascript 调用的函数中执行此操作,因此它会发生 panic 。 (当我在 playground 中运行它时,我也会得到 Uncaught TypeError: r is not a function ,但这只是早期错误的后果。)
我想你要做的是等待doRequest完成,打印值并返回,但这不起作用。为此,您需要使用 native Javascript promise 或其他一些异步机制。


标签:
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号