为什么以下代码中出现死锁?我正在尝试将某些东西从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不启动任何东西,只接收一个通道,因此它被阻塞,并且没有其他goroutine正在运行,因此main不可能再次唤醒,因此运行时会出现恐慌。

如果我没记错的话,与普通的Go语言不同,GopherJS不会关闭所有文件并在main退出的情况下退出(部分原因是:那到底是什么意思?与Go程序最接近的类比就是关闭网页!的问题。所以GopherJS不会那样做。)。因此,严格来说,在GopherJS中,无需执行使main保持 Activity 状态的操作。

也就是说,如果您在末尾说(例如)time.Sleep(time.Hour),则在所有goroutine仍处于睡眠状态(严格来说)时,main最终将唤醒,运行时知道,因此在这种情况下不会惊慌。

至于您的实际test函数,一旦尝试使用它,您会收到一条相关的错误消息:Uncaught Error: runtime error: cannot block in JavaScript callback, fix by wrapping code in goroutinetest在通道上进行了阻塞调用,而GopherJS不允许在直接从Javascript调用的函数中进行此操作,因此会感到恐慌。 (当我在playground中运行它时,我也得到Uncaught TypeError: r is not a function,但这只是先前错误的结果。)
我认为您正在尝试做的是等待doRequest完成,打印值并返回,但这是行不通的。为此,您需要使用本机Javascript Promise或其他异步机制。

10-07 19:19
查看更多