You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 20:20:24