如何从 Go web assembly 中 "throw" JS 错误?
How to "throw" JS error from Go web assembly?
我试过了
js.Global().Call("throw", "yeet")
但回来了
panic: 1:1: expected operand, found 'type' [recovered]
wasm_exec.f7bab17184626fa7f3ebe6c157d4026825842d39bfae444ef945e60ec7d3b0f1.js:51 panic: syscall/js: Value.Call: property throw is not a function, got undefined
我看到在 syscall/js
中定义了一个 Error
类型,但是没有关于抛出它的任何内容 https://golang.org/pkg/syscall/js/#Error
不可能 throw
来自 WebAssembly 的 JS 错误。在 JS 中,当您 throw
一个值时,JS 运行时会将堆栈展开到最近的 try
块,或者记录一个未捕获的错误。 WASM 执行是在无法直接访问 JS 堆栈的单独执行环境中的隔离沙箱中执行的。来自 WASM docs:
Each WebAssembly module executes within a sandboxed environment separated from the host runtime using fault isolation techniques.
如果 WASM 调用抛出的 JS 代码,错误将被 WASM 运行时捕获并处理,就好像 WASM 代码已经崩溃一样。 WASM 可以访问 traps,但它们旨在在运行时级别立即停止执行(并且未在 Go 的 syscall/js
模块中实现)。
表示可能失败的代码执行的惯用方法是 return Promise
,然后 resolve
承诺成功或 reject
失败。调用 JS 代码可以在 try/catch
块中等待 promise 执行并在那里处理错误,或者使用 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
}
然后,在你的 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);
});
我不同意@superhawk610
It's not possible to throw a JS error from WebAssembly
可以扔,但实用性如何?根据浏览器的不同,您甚至可能获得一些可读的堆栈跟踪,但大多数情况下有一些 Promise
逻辑,如 @superhawk610 解释会更有意义。但是,如果你真的不想抛出异常,这里是一个简单的例子。
例子
1.你可以提供 throw 函数 stub
// Throw function stub to throw javascript exceptions
// Without func body!
func Throw(exception string, message string)
2。然后通过创建 yourpkg_js.s 文件
为汇编程序提供提示
// Throw enables to throw javascript exceptions
TEXT ·Throw(SB), NOSPLIT, [=11=]
CallImport
RET
3。通过扩展 wasm_exec / 你的 wasm importObject
添加 js 回调
this.importObject = {
go: {
// ...
// func Throw(exception string, message string)
'<your-pkg-import-path>.Throw': (sp) => {
const exception = loadString(sp + 8)
const message = loadString(sp + 24)
const throwable = globalThis[exception](message)
throw throwable
}
}
}
然后您可以通过提供 Error
class 名称和消息来抛出错误。例如
func main () {
Throw("TypeError", "invalid arguments")
}
我试过了
js.Global().Call("throw", "yeet")
但回来了
panic: 1:1: expected operand, found 'type' [recovered] wasm_exec.f7bab17184626fa7f3ebe6c157d4026825842d39bfae444ef945e60ec7d3b0f1.js:51 panic: syscall/js: Value.Call: property throw is not a function, got undefined
我看到在 syscall/js
中定义了一个 Error
类型,但是没有关于抛出它的任何内容 https://golang.org/pkg/syscall/js/#Error
不可能 throw
来自 WebAssembly 的 JS 错误。在 JS 中,当您 throw
一个值时,JS 运行时会将堆栈展开到最近的 try
块,或者记录一个未捕获的错误。 WASM 执行是在无法直接访问 JS 堆栈的单独执行环境中的隔离沙箱中执行的。来自 WASM docs:
Each WebAssembly module executes within a sandboxed environment separated from the host runtime using fault isolation techniques.
如果 WASM 调用抛出的 JS 代码,错误将被 WASM 运行时捕获并处理,就好像 WASM 代码已经崩溃一样。 WASM 可以访问 traps,但它们旨在在运行时级别立即停止执行(并且未在 Go 的 syscall/js
模块中实现)。
表示可能失败的代码执行的惯用方法是 return Promise
,然后 resolve
承诺成功或 reject
失败。调用 JS 代码可以在 try/catch
块中等待 promise 执行并在那里处理错误,或者使用 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
}
然后,在你的 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);
});
我不同意@superhawk610
It's not possible to throw a JS error from WebAssembly
可以扔,但实用性如何?根据浏览器的不同,您甚至可能获得一些可读的堆栈跟踪,但大多数情况下有一些 Promise
逻辑,如 @superhawk610 解释会更有意义。但是,如果你真的不想抛出异常,这里是一个简单的例子。
例子
1.你可以提供 throw 函数 stub
// Throw function stub to throw javascript exceptions
// Without func body!
func Throw(exception string, message string)
2。然后通过创建 yourpkg_js.s 文件
为汇编程序提供提示// Throw enables to throw javascript exceptions
TEXT ·Throw(SB), NOSPLIT, [=11=]
CallImport
RET
3。通过扩展 wasm_exec / 你的 wasm importObject
添加 js 回调this.importObject = {
go: {
// ...
// func Throw(exception string, message string)
'<your-pkg-import-path>.Throw': (sp) => {
const exception = loadString(sp + 8)
const message = loadString(sp + 24)
const throwable = globalThis[exception](message)
throw throwable
}
}
}
然后您可以通过提供 Error
class 名称和消息来抛出错误。例如
func main () {
Throw("TypeError", "invalid arguments")
}