Golang中如何捕获调用"syscall/js"函数时的异常?
Golang中如何捕获调用"syscall/js"函数时的异常?
我正在使用 syscall/js 包,需要帮助找到一种方法来捕获调用 JavaScript 函数时抛出的异常。
以下是一个示例:
value := js.Global().Get("window").Get("localStorage")
...
如果你在浏览器中禁用了对本地存储的访问,那么它会引发以下异常:

并且无法恢复你的 wasm 代码。 感谢任何帮助。
更多关于Golang中如何捕获调用"syscall/js"函数时的异常?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
感谢 @skillian
不幸的是,它没有起作用。JS 调用异常并没有导致 Go 代码 panic,因此无法进行恢复。
Go 的 wasm 代码仅仅……在 .Get("localstorage") 这一行……停止了。
.Get("localstorage")
更多关于Golang中如何捕获调用"syscall/js"函数时的异常?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
syscall/js 的文档说明,当值不是 JavaScript 对象时,js.Value.Get 会引发恐慌,因此你应该能够“捕获异常”,就像在其他 Go 代码中从恐慌中恢复一样:
func tryGet(v js.Value, p string) (result js.Value, err error) {
defer func() {
if x := recover(); x != nil {
var ok bool
if err, ok = x.(error); !ok {
err = fmt.Errorf("%v", x)
}
}
}()
return v.Get(p), nil
}
看起来你可能需要在JavaScript端捕获它,然后将其传回Go。
我不熟悉JavaScript,所以不知道这是否符合惯用法,但我写了:
function tryGet() {
try {
var source = arguments[0];
for (var i = 1; i < arguments.length; i++)
source = source[arguments[i]];
return [source, null];
}
catch (err) {
return [null, err];
}
}
然后在我的Go代码中:
func tryGet(source js.Value, path ...string) (js.Value, error) {
tryGetArgs := make([]any, len(path)+1)
tryGetArgs[0] = source
for i, v := range path {
tryGetArgs[i+1] = js.ValueOf(v)
}
arr := js.Global().Call("tryGet", tryGetArgs...)
if arr1 := arr.Index(1); !arr1.Equal(js.Null()) {
return js.Value{}, &js.Error{arr1}
}
return arr.Index(0), nil
}
func main() {
keepMainRunning := make(chan struct{})
v, err := tryGet(js.Global(), "window", "localStorage")
if err != nil {
alert(err.Error())
return
}
fmt.Println("result of tryGet:", v)
<-keepMainRunning
}
在我的电脑上,访问 window.localStorage 没有抛出异常,但如果我使用无效的属性名,我会从 tryGet 的第二个返回值得到一个错误。
在Go WebAssembly中使用syscall/js调用JavaScript函数时,可以通过js.Global().Call("eval", ...)结合recover()来捕获异常。以下是具体的实现方法:
package main
import (
"syscall/js"
)
// SafeCall 安全调用JavaScript函数,捕获异常
func SafeCall(fn js.Value, args ...interface{}) (result js.Value, err error) {
defer func() {
if r := recover(); r != nil {
err = r.(error)
}
}()
result = fn.Invoke(args...)
return result, nil
}
// 使用示例
func main() {
// 获取localStorage
localStorage := js.Global().Get("window").Get("localStorage")
// 安全调用setItem
_, err := SafeCall(localStorage.Get("setItem"), "key", "value")
if err != nil {
// 处理异常
js.Global().Get("console").Call("log", "Error:", err.Error())
}
// 或者使用更通用的异常捕获包装器
js.Global().Set("safeGetItem", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
return js.Global().Call("eval", `
try {
return window.localStorage.getItem(` + args[0].String() + `);
} catch(e) {
return e.toString();
}
`)
}))
}
对于更复杂的场景,可以创建一个通用的异常捕获包装器:
// TryCatch 使用JavaScript的try-catch包装函数调用
func TryCatch(fn func()) (exception js.Value) {
js.Global().Set("__go_exception", js.Undefined())
js.Global().Call("eval", `
try {
__go_fn();
} catch(e) {
__go_exception = e;
}
`)
// 定义JavaScript端的回调函数
js.Global().Set("__go_fn", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
fn()
return nil
}))
// 执行eval
js.Global().Call("eval", `
try {
__go_fn();
} catch(e) {
__go_exception = e;
}
`)
exception = js.Global().Get("__go_exception")
if !exception.IsUndefined() {
panic(js.Error{exception})
}
return exception
}
// 使用示例
func exampleUsage() {
TryCatch(func() {
// 可能抛出异常的代码
js.Global().Get("window").Get("localStorage").Call("setItem", "test", "value")
})
}
另外,也可以直接使用JavaScript的try-catch通过eval执行:
// ExecWithCatch 使用eval执行JavaScript代码并捕获异常
func ExecWithCatch(jsCode string) (result js.Value, err error) {
defer func() {
if r := recover(); r != nil {
err = r.(error)
}
}()
wrappedCode := `
try {
` + jsCode + `
} catch(e) {
throw e;
}
`
result = js.Global().Call("eval", wrappedCode)
return result, nil
}
// 使用示例
func main() {
// 直接执行JavaScript代码并捕获异常
_, err := ExecWithCatch(`window.localStorage.setItem("key", "value")`)
if err != nil {
js.Global().Get("console").Call("log", "Caught exception:", err.Error())
}
}
这些方法通过在JavaScript层面使用try-catch来捕获异常,然后通过Go的recover()机制将异常传递回Go代码中处理。

