Trabalhando com WebAssembly e Go: nível avançado
O WebAssembly (WASM) abre novos horizontes para o desenvolvimento web, permitindo executar código de alto desempenho escrito em linguagens diferentes do JavaScript. Go (Golang) com seu compilador para WASM e modelo simples de concorrência é um excelente candidato para criar módulos web complexos. Neste artigo, exploraremos técnicas avançadas de integração de Go e WebAssembly: trabalho com memória, transferência de estruturas de dados complexas, comunicação bidirecional com JavaScript e otimização de desempenho.
1. Transferência de estruturas de dados complexas entre Go e JavaScript
A transferência básica de números e strings via syscall/js é simples, mas para aplicações reais isso não é suficiente. A abordagem avançada envolve a serialização de estruturas complexas (slices, maps, tipos personalizados) em JSON ou formato binário.
Serialização via JSON
O método mais simples e universal é usar encoding/json. Você exporta uma função que recebe uma string JSON, desserializa-a em uma estrutura Go, processa e retorna o resultado de volta 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}Trabalho direto com memória (protocolo binário)
Para desempenho máximo, você pode transferir dados através da memória linear do WASM. Você exporta funções para escrever/ler da memória e passa ponteiros (como números inteiros) para o JavaScript. Este método é mais complexo, mas evita a sobrecarga de análise de JSON.
// Exportação de função para escrever na memória//go:wasmexport allocateMemoryfunc allocateMemory(size int) uintptr { // Usa C.malloc ou seu próprio alocador // Retorna o ponteiro}
//go:wasmexport getMemoryBufferfunc getMemoryBuffer() uintptr { // Retorna o início do buffer}No JavaScript, você usa WebAssembly.Memory e Uint8Array para ler/escrever nos endereços obtidos.
2. Chamando JavaScript a partir de Go e manipulando o DOM
O pacote syscall/js permite chamar qualquer função JavaScript e manipular o DOM. O nível avançado envolve a criação de interfaces reativas e tratamento de eventos.
Criação e atualização de elementos do 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 {}}Tratamento de eventos no lado do 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