Travailler avec WebAssembly et Go : niveau avancé
WebAssembly (WASM) ouvre de nouveaux horizons pour le développement web, permettant d'exécuter du code haute performance écrit dans des langages autres que JavaScript. Go (Golang) avec son compilateur vers WASM et son modèle de concurrence simple est un excellent candidat pour créer des modules web complexes. Dans cet article, nous examinerons les techniques avancées d'intégration de Go et WebAssembly : la gestion de la mémoire, la transmission de structures de données complexes, la communication bidirectionnelle avec JavaScript et l'optimisation des performances.
1. Transmission de structures de données complexes entre Go et JavaScript
La transmission de base de nombres et de chaînes via syscall/js est simple, mais elle ne suffit pas pour des applications réelles. Une approche avancée implique la sérialisation de structures complexes (tranches, maps, types personnalisés) en JSON ou en format binaire.
Sérialisation via JSON
La méthode la plus simple et la plus universelle consiste à utiliser encoding/json. Vous exportez une fonction qui prend une chaîne JSON, la désérialise en une structure Go, la traite et renvoie le résultat sous forme de 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}Travail direct avec la mémoire (protocole binaire)
Pour des performances maximales, vous pouvez transmettre des données via la mémoire linéaire WASM. Vous exportez des fonctions pour écrire/lire dans la mémoire et transmettez des pointeurs (sous forme d'entiers) à JavaScript. Cette méthode est plus complexe, mais elle évite les frais généraux d'analyse JSON.
// Export d'une fonction pour écrire dans la mémoire//go:wasmexport allocateMemoryfunc allocateMemory(size int) uintptr { // Utilisez C.malloc ou votre propre allocateur // Retourne le pointeur}
//go:wasmexport getMemoryBufferfunc getMemoryBuffer() uintptr { // Retourne le début du tampon}En JavaScript, vous utilisez WebAssembly.Memory et Uint8Array pour lire/écrire aux adresses obtenues.
2. Appel de JavaScript depuis Go et gestion du DOM
Le package syscall/js permet d'appeler n'importe quelle fonction JavaScript et de manipuler le DOM. Le niveau avancé implique la création d'interfaces réactives et la gestion d'événements.
Création et mise à jour d'éléments 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 {}}Gestion d'événements côté 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