【问题标题】:How to "throw" JS error from Go web assembly?如何从 Go Web 程序集“抛出”JS 错误?
【发布时间】:2021-07-29 21:35:56
【问题描述】:

我试过了

js.Global().Call("throw", "yeet")

回来了

恐慌:1:1:预期的操作数,找到“类型”[已恢复] wasm_exec.f7bab17184626fa7f3ebe6c157d4026825842d39bfae444ef945e60ec7d3b0f1.js:51 恐慌:系统调用/js:Value.Call:属性抛出不是函数,未定义

我看到syscall/js 中定义了一个Error 类型,但没有什么可以抛出它https://golang.org/pkg/syscall/js/#Error

【问题讨论】:

  • 写一个简单的 JS 函数抛出参数然后让 Go 调用那个函数怎么样?
  • @leafbebop 很棒的建议,虽然这会导致恐慌并且 js 胶水会抛出一堆奇怪的错误,比如errors.ts:19 Uncaught Error: (intermediate value)(intermediate value)(intermediate value).create is not a function。我可能会有更好的时间以自己的方式返回错误消息
  • 我认为从 wasm 引发异常的惯用方法是引入 trap,但看起来 syscall/js 还不支持。 documentation for syscall/js 声明它是实验性的,并不打算作为一个完整的 API 运行,因此它可能会在未来实现。
  • Error 类型仅用于允许在 wasm 执行期间发生的字符串化错误(请参阅the source)。如果你调用一个 JS 函数并抛出异常,你会看到 panic: Javascript error: {ERROR_MESSAGE}

标签: javascript go webassembly


【解决方案1】:

不可能 throw 来自 WebAssembly 的 JS 错误。在 JS 中,当您 throw 一个值时,JS 运行时会将堆栈展开到最近的 try 块,或者记录一个未捕获的错误。 WASM 执行是在一个独立的沙箱中执行的,它位于一个无法直接访问 JS 堆栈的单独执行环境中。来自 WASM docs

每个 WebAssembly 模块都在使用故障隔离技术与主机运行时分离的沙盒环境中执行。

如果 WASM 调用抛出的 JS 代码,则错误将被 WASM 运行时捕获并像 WASM 代码发生恐慌一样进行处理。 WASM 可以访问 traps,但它们旨在在运行时级别立即停止执行(并且未在 Go 的 syscall/js 模块中实现)。

表示可能失败的代码执行的惯用方法是返回Promise,然后返回resolve 表示成功或reject 失败。调用 JS 代码可以在 try/catch 块中等待承诺执行并在那里处理错误,或者使用承诺链接并在 .catch() 回调中处理错误。这是一个简短的例子:

func main() {
    c := make(chan struct{})

    js.Global().Set("doSomething", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
        handler := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
            resolve := args[0]
            reject := args[1]

            go func() {
                data, err := doSomeWork()
                if err != nil {
                    // err should be an instance of `error`, eg `errors.New("some error")`
                    errorConstructor := js.Global().Get("Error")
                    errorObject := errorConstructor.New(err.Error())
                    reject.Invoke(errorObject)
                } else {
                    resolve.Invoke(js.ValueOf(data))
                }
            }()

            return nil
        })

        promiseConstructor := js.Global().Get("Promise")
        return promiseConstructor.New(handler)
    })

    <-c
}

然后,在你的 JS 代码中:

(async () => {
  try {
    await window.doSomething();
  } catch (err) {
    console.log('caught error from WASM:', err);
  }
}();

window.doSomething()
  .then(_ => /* ... */)
  .catch(err => {
    console.log('caught error from WASM:', err);
  });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-24
    • 1970-01-01
    • 2011-06-19
    • 2018-02-11
    • 2012-06-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多