Go WASM实现简易Await触发goroutine死锁错误求助
Go WASM实现Await触发死锁的原因与解决办法
问题原因分析
你遇到的死锁本质是Go WASM的执行模型限制导致的:
- Go WASM运行在浏览器的单线程事件循环中,所有JS回调(包括你注册的
testMethInWasm)都在同一个goroutine内执行。 - 你的
Await函数通过<-done阻塞了当前goroutine,直接卡住了整个事件循环。 - Promise的
then回调需要等待当前JS调用栈清空后才能执行,但因为当前goroutine一直阻塞在channel接收上,事件循环根本没有机会处理Promise的回调逻辑,导致done通道永远不会被写入,最终所有goroutine进入休眠状态,触发死锁。
解决方法
核心思路是不要在JS回调函数内做阻塞操作,通过goroutine将阻塞逻辑异步化,给事件循环留出处理Promise回调的机会:
修改后的代码如下:
package main import ( "fmt" "syscall/js" ) func main() { js.Global().Set("testMethInWasm", js.FuncOf(func(this js.Value, args []js.Value) any { // 将Await逻辑放到新goroutine中执行,避免阻塞当前JS回调 go func() { r := Await(js.Global().Call("eval", `Promise.resolve(true)`)) fmt.Println(fmt.Sprintf("result:%v", r)) }() return nil })) select {} } func Await(p js.Value) js.Value { var done = make(chan int) var r js.Value p.Call("then", js.FuncOf(func(this js.Value, args []js.Value) any { r = args[0] done <- 0 return nil })) <-done return r }
原理说明
- 启动新goroutine后,当前JS回调会立即返回,浏览器事件循环不会被阻塞,能够正常处理Promise的
then回调。 - Promise回调执行时会向
done通道写入信号,此时goroutine中的<-done会收到信号,继续执行后续逻辑,避免了死锁。
内容的提问来源于stack exchange,提问作者chikadance
相关产品推荐
相关产品推荐

