如何从 Go Web 程序集“抛出”JS 错误?

Bri*_*ica 6 javascript go webassembly

我试过

js.Global().Call("throw", "yeet")
Run Code Online (Sandbox Code Playgroud)

但回来了

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

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

sup*_*610 9

throwWebAssembly不可能出现JS 错误。在 JS 中,当您throw输入值时,JS 运行时会将堆栈展开到最近的try块,或记录未捕获的错误。WASM 执行是在独立的执行环境中的隔离沙箱中执行的,无法直接访问 JS 堆栈。来自 WASM文档

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

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

表示可能失败的代码执行的惯用方法是返回 a Promise,然后返回resolve成功时的承诺或reject失败时的承诺。调用 JS 代码可以等待块内的 Promise 执行try/catch并处理其中的错误,或者使用 Promise 链并在.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
}
Run Code Online (Sandbox Code Playgroud)

然后,在你的 JS 代码中:

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

或者

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


mku*_*gla 6

我不同意@superhawk610 的观点

\n
\n

不可能从 WebAssembly 抛出 JS 错误

\n
\n

好吧,你可以扔它,但它有多实用呢?根据浏览器的不同,您甚至可能会获得一些可读的堆栈跟踪,但大多数情况下,解释一些像@superhawk610Promise这样的逻辑会更有意义。但是,如果您真的不想抛出异常,这里是一个简单的例子。

\n

例子

\n

1. 可以提供 throw 函数存根

\n
// Throw function stub to throw javascript exceptions\n// Without func body!\nfunc Throw(exception string, message string)\n
Run Code Online (Sandbox Code Playgroud)\n

2. 然后通过创建 yourpkg_js.s 文件为汇编器提供提示

\n
// Throw enables to throw javascript exceptions\nTEXT \xc2\xb7Throw(SB), NOSPLIT, $0\n  CallImport\n  RET\n
Run Code Online (Sandbox Code Playgroud)\n

3. 通过扩展 wasm_exec / 你的 wasm importObject 添加 js 回调

\n
// Throw enables to throw javascript exceptions\nTEXT \xc2\xb7Throw(SB), NOSPLIT, $0\n  CallImport\n  RET\n
Run Code Online (Sandbox Code Playgroud)\n

然后您可以通过提供Error类名和消息来抛出错误。例如

\n
this.importObject = {\n  go: {\n    // ...\n\n    // func Throw(exception string, message string)\n    \'<your-pkg-import-path>.Throw\': (sp) => {\n      const exception = loadString(sp + 8)\n      const message = loadString(sp + 24)\n      const throwable = globalThis[exception](message)\n      throw throwable\n    }\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n