Working with WebAssembly and Go: Advanced Integration Techniques

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Working with WebAssembly and Go: Advanced Level



WebAssembly (WASM) opens new horizons for web development, allowing you to execute high-performance code written in languages other than JavaScript. Go (Golang) with its compiler to WASM and simple concurrency model is an excellent candidate for creating complex web modules. In this article, we will look at advanced techniques for integrating Go and WebAssembly: working with memory, passing complex data structures, two-way communication with JavaScript, and performance optimization.



1. Passing Complex Data Structures Between Go and JavaScript



Basic passing of numbers and strings via syscall/js is simple, but it is not enough for real applications. An advanced approach involves serializing complex structures (slices, maps, custom types) into JSON or binary format.



Serialization via JSON

The simplest and most universal method is to use encoding/json. You export a function that takes a JSON string, deserializes it into a Go structure, processes it, and returns the result back as 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}


Direct Memory Manipulation (Binary Protocol)

For maximum performance, you can pass data through WASM linear memory. You export functions for writing/reading from memory and pass pointers (as integers) to JavaScript. This method is more complex but avoids the overhead of JSON parsing.



// Export function for writing to memory//go:wasmexport allocateMemoryfunc allocateMemory(size int) uintptr {    // Use C.malloc or custom allocator    // Return pointer}

//go:wasmexport getMemoryBufferfunc getMemoryBuffer() uintptr { // Return buffer start}


In JavaScript, you use WebAssembly.Memory and Uint8Array to read/write at the obtained addresses.



2. Calling JavaScript from Go and DOM Manipulation



The syscall/js package allows you to call any JavaScript functions and manipulate the DOM. The advanced level involves creating reactive interfaces and handling events.



Creating and Updating DOM Elements

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 {}}


Event Handling on the Go Side

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

Blogs

Book Recommendations