如何在出现错误并退出(代码:2)后保持Golang WebAssembly实例持续运行
sendBytes? Problem Statement
I've written a Go WebAssembly function to receive byte data from JavaScript, but when I pass non-Uint8Array data to it, the entire WASM instance crashes and I have to restart it. Here's my code:
func sendBytes(this js.Value, args []js.Value) interface{} { if len(args) < 1 { return 0 } array := args[0] fmt.Println(array.Type()) buf := make([]byte, array.Length()) n := js.CopyBytesToGo(buf, array) fmt.Println(buf) return n } func registerCallbacks() { js.Global().Set("sendBytes", js.FuncOf(sendBytes)) }How can I ensure the WASM instance keeps running no matter what errors occur?
Answer
Great question—this is a super common pitfall when working with Go WASM and JavaScript interop! The core issue here is that js.CopyBytesToGo will panic if you pass a value that isn't a valid Uint8Array (or compatible typed array with a byte-aligned layout). Unrecovered panics in Go WASM take the entire instance down, so we need two key fixes: input validation and panic recovery.
Here's how to make your function crash-resistant:
1. Validate input type before processing
First, we'll add a check to ensure the input is actually a Uint8Array before attempting any byte copying. This blocks invalid inputs from ever reaching the panic-prone function:
func sendBytes(this js.Value, args []js.Value) interface{} { // Check for missing input if len(args) < 1 { return map[string]interface{}{ "success": false, "error": "no input value provided", } } input := args[0] uint8ArrayConstructor := js.Global().Get("Uint8Array") // Verify the input is a Uint8Array instance if input.Type() != js.TypeObject || !input.InstanceOf(uint8ArrayConstructor) { return map[string]interface{}{ "success": false, "error": "input must be a Uint8Array", } } // Now we can safely process the valid input buf := make([]byte, input.Length()) bytesCopied := js.CopyBytesToGo(buf, input) fmt.Println("Received bytes:", buf) return map[string]interface{}{ "success": true, "bytesCopied": bytesCopied, "receivedData": buf, // Optional: return data back to JS if needed } }
2. Add a panic recovery safety net
Even with strict type checks, edge cases (like a detached typed array or unexpected JS value quirks) could still trigger a panic. Adding a deferred recover ensures any panics are caught, logged, and don't take down the entire WASM instance:
func sendBytes(this js.Value, args []js.Value) interface{} { // Use a named return value to easily update results in the recover handler var result = map[string]interface{}{"success": true} // Catch and recover from any unexpected panics defer func() { if r := recover(); r != nil { fmt.Printf("Recovered from panic in sendBytes: %v\n", r) result["success"] = false result["error"] = "unexpected error processing input" } }() // Input validation if len(args) < 1 { result["success"] = false result["error"] = "no input value provided" return result } input := args[0] uint8ArrayConstructor := js.Global().Get("Uint8Array") if input.Type() != js.TypeObject || !input.InstanceOf(uint8ArrayConstructor) { result["success"] = false result["error"] = "input must be a Uint8Array" return result } // Safe byte copying buf := make([]byte, input.Length()) bytesCopied := js.CopyBytesToGo(buf, input) fmt.Println("Received bytes:", buf) result["bytesCopied"] = bytesCopied result["receivedData"] = buf return result }
3. Return structured responses to JavaScript
Instead of returning a plain number like 0, using a structured object with success/error flags makes it easy for your JavaScript code to handle failures gracefully without guessing what went wrong.
Why this works
- Type validation filters out invalid inputs before they can cause a panic.
- Panic recovery acts as a safety net for unexpected edge cases, keeping the WASM instance alive.
- Structured responses improve clarity and interoperability between Go WASM and JavaScript.
内容的提问来源于stack exchange,提问作者Igor65777

