Trabajo con WebAssembly y Go: nivel avanzado
WebAssembly (WASM) abre nuevos horizontes para el desarrollo web, permitiendo ejecutar código de alto rendimiento escrito en lenguajes distintos a JavaScript. Go (Golang), con su compilador a WASM y su modelo simple de concurrencia, es un excelente candidato para crear módulos web complejos. En este artículo exploraremos técnicas avanzadas de integración de Go y WebAssembly: trabajo con memoria, transferencia de estructuras de datos complejas, comunicación bidireccional con JavaScript y optimización del rendimiento.
1. Transferencia de estructuras de datos complejas entre Go y JavaScript
La transferencia básica de números y cadenas a través de syscall/js es simple, pero no es suficiente para aplicaciones reales. Un enfoque avanzado implica la serialización de estructuras complejas (slices, maps, tipos personalizados) en JSON o formato binario.
Serialización mediante JSON
El método más simple y universal es usar encoding/json. Exportas una función que recibe una cadena JSON, la deserializa en una estructura de Go, la procesa y devuelve el resultado como JSON.
// main.gopackage main
import ( "encoding/json" "syscall/js")
type InputData struct { Name string `json:"name"` Value float64 `json:"value"`}
type OutputData struct { Greeting string `json:"greeting"` Square float64 `json:"square"`}
func processData(this js.Value, args []js.Value) interface{} { if len(args) < 1 { return "Error: expected JSON string" } inputJSON := args[0].String()
var input InputData if err := json.Unmarshal([]byte(inputJSON), &input); err != nil { return "Error: " + err.Error() }
output := OutputData{ Greeting: "Hello, " + input.Name, Square: input.Value * input.Value, }
resultJSON, _ := json.Marshal(output) return string(resultJSON)}
func main() { c := make(chan struct{}, 0) js.Global().Set("processData", js.FuncOf(processData)) <-c}Trabajo directo con memoria (protocolo binario)
Para máximo rendimiento, puedes transferir datos a través de la memoria lineal de WASM. Exportas funciones para escribir/leer de la memoria y pasas punteros (como números enteros) a JavaScript. Este método es más complejo, pero evita la sobrecarga de analizar JSON.
// Exportar función para escribir en memoria//go:wasmexport allocateMemoryfunc allocateMemory(size int) uintptr { // Usar C.malloc o tu propio asignador // Devolver el puntero}
//go:wasmexport getMemoryBufferfunc getMemoryBuffer() uintptr { // Devolver el inicio del buffer}En JavaScript usas WebAssembly.Memory y Uint8Array para leer/escribir en las direcciones obtenidas.
2. Llamar a JavaScript desde Go y manipular el DOM
El paquete syscall/js permite llamar a cualquier función de JavaScript y manipular el DOM. El nivel avanzado implica la creación de interfaces reactivas y el manejo de eventos.
Creación y actualización de elementos del DOM
func appendDiv(this js.Value, args []js.Value) interface{} { document := js.Global().Get("document") body := document.Get("body")
newDiv := document.Call("createElement", "div") newDiv.Set("innerHTML", "<h2>Hello from Go WASM!</h2>") newDiv.Get("style").Set("color", "blue") body.Call("appendChild", newDiv) return nil}
func main() { js.Global().Set("appendDiv", js.FuncOf(appendDiv)) select {}}Manejo de eventos en el lado de Go
func setupClickHandler(this js.Value, args []js.Value) interface{} { document := js.Global().Get("document") button := document.Call("getElementById", "myButton")
clickCallback := js.FuncOf(func(this js.Value, args []js