Golang WebAssembly使用示例与最佳实践

Golang WebAssembly使用示例与最佳实践 有没有人拥有关于Web Assembly的学习资料或示例代码?

2 回复

我会从这里开始:

Go 图标

Go Wiki: WebAssembly - The Go Programming Language

Go Gopher 标志

Go Wiki: WebAssembly - Go 编程语言

另外请注意:大多数使用 Go 与 WASM 的人都会使用 TinyGo 进行编译,以获得更小的包体积。请查看他们的 WASM 页面:

TinyGo 图标

TinyGo

WebAssembly

TinyGo 对于编译在浏览器中使用的程序(WASM)以及在服务器和其他边缘设备上使用的程序(WASI)非常有用。

以下是其他一些可能有用的链接:

golangbot 图标

golangbot – 4 Feb 24

golangbot 社交分享图片

WebAssembly: 使用 Go 的 WebAssembly 入门

这是一个关于 WebAssembly 以及如何使用 WebAssembly 在浏览器中交叉编译和运行 Go 程序的教程。

permify.co 图标

permify.co

WASM Go 图片

WebAssembly with Go: 将 Web 应用提升到新水平

这篇教程文章演示了我们如何将 WebAssembly (WASM) 与 Golang 集成,并在我们的开源项目中使用它来简化功能并提供更丰富的用户体验。

更多关于Golang WebAssembly使用示例与最佳实践的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


以下是一个完整的Go WebAssembly示例,包含前后端交互的最佳实践:

// main.go
package main

import (
    "fmt"
    "syscall/js"
    "time"
)

func main() {
    // 注册Go函数到JavaScript全局对象
    js.Global().Set("goAdd", js.FuncOf(add))
    js.Global().Set("goFibonacci", js.FuncOf(fibonacci))
    js.Global().Set("goProcessData", js.FuncOf(processData))
    
    // 保持WebAssembly实例运行
    <-make(chan bool)
}

// 基础计算示例
func add(this js.Value, args []js.Value) interface{} {
    if len(args) != 2 {
        return js.ValueOf("需要两个参数")
    }
    a := args[0].Float()
    b := args[1].Float()
    return js.ValueOf(a + b)
}

// 性能敏感算法示例
func fibonacci(this js.Value, args []js.Value) interface{} {
    if len(args) != 1 {
        return js.ValueOf(0)
    }
    n := args[0].Int()
    
    if n <= 1 {
        return js.ValueOf(n)
    }
    
    a, b := 0, 1
    for i := 2; i <= n; i++ {
        a, b = b, a+b
    }
    return js.ValueOf(b)
}

// 复杂数据处理示例
func processData(this js.Value, args []js.Value) interface{} {
    if len(args) != 1 {
        return js.ValueOf(nil)
    }
    
    // 从JavaScript接收ArrayBuffer
    data := args[0]
    length := data.Get("byteLength").Int()
    uint8Array := js.Global().Get("Uint8Array").New(data)
    
    // 在Go中处理数据
    processed := make([]byte, length)
    for i := 0; i < length; i++ {
        processed[i] = uint8Array.Index(i).Int() ^ 0xFF // 简单反转操作
    }
    
    // 返回处理后的数据
    jsArray := js.Global().Get("Uint8Array").New(length)
    for i, v := range processed {
        jsArray.SetIndex(i, v)
    }
    return jsArray
}

// 异步操作示例
func asyncOperation(this js.Value, args []js.Value) interface{} {
    promise := js.Global().Get("Promise").New(js.FuncOf(func(this js.Value, promiseArgs []js.Value) interface{} {
        resolve := promiseArgs[0]
        
        go func() {
            // 模拟耗时操作
            time.Sleep(2 * time.Second)
            
            // 返回结果
            result := map[string]interface{}{
                "status": "completed",
                "timestamp": time.Now().Unix(),
            }
            resolve.Invoke(js.ValueOf(result))
        }()
        
        return nil
    }))
    
    return promise
}
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Go WebAssembly 示例</title>
</head>
<body>
    <h1>Go WebAssembly 演示</h1>
    
    <div>
        <h3>基础计算</h3>
        <button onclick="testAdd()">测试加法</button>
        <div id="addResult"></div>
    </div>
    
    <div>
        <h3>性能计算</h3>
        <input type="number" id="fibInput" value="40">
        <button onclick="testFibonacci()">计算斐波那契</button>
        <div id="fibResult"></div>
    </div>
    
    <div>
        <h3>数据处理</h3>
        <button onclick="testDataProcessing()">处理二进制数据</button>
        <div id="dataResult"></div>
    </div>
    
    <script>
        // 加载WebAssembly模块
        const go = new Go();
        
        async function init() {
            try {
                const result = await WebAssembly.instantiateStreaming(
                    fetch("main.wasm"),
                    go.importObject
                );
                go.run(result.instance);
                console.log("WebAssembly 加载成功");
            } catch (err) {
                console.error("加载失败:", err);
            }
        }
        
        // 测试函数
        function testAdd() {
            const result = goAdd(15, 27);
            document.getElementById('addResult').textContent = `15 + 27 = ${result}`;
        }
        
        function testFibonacci() {
            const input = document.getElementById('fibInput').value;
            const start = performance.now();
            const result = goFibonacci(parseInt(input));
            const time = performance.now() - start;
            document.getElementById('fibResult').textContent = 
                `fib(${input}) = ${result}, 耗时: ${time.toFixed(2)}ms`;
        }
        
        function testDataProcessing() {
            // 创建测试数据
            const data = new Uint8Array(1024 * 1024); // 1MB数据
            for (let i = 0; i < data.length; i++) {
                data[i] = i % 256;
            }
            
            const start = performance.now();
            const processed = goProcessData(data.buffer);
            const time = performance.now() - start;
            
            document.getElementById('dataResult').textContent = 
                `处理了 ${data.length} 字节, 耗时: ${time.toFixed(2)}ms`;
        }
        
        // 初始化
        init();
    </script>
</body>
</html>
# 编译命令
# 1. 编译为WebAssembly
GOOS=js GOARCH=wasm go build -o main.wasm main.go

# 2. 复制必要的JavaScript支持文件
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .

# 3. 启动本地服务器
python3 -m http.server 8080

关键实践要点:

  1. 内存管理:通过ArrayBuffer传递大数据,避免频繁的JavaScript-Go边界调用
  2. 错误处理:在Go函数中验证参数,返回适当的错误信息
  3. 异步操作:使用Promise处理长时间运行的任务
  4. 类型转换:正确转换JavaScript和Go之间的数据类型
  5. 性能优化:将计算密集型任务放在Go端执行

项目结构:

project/
├── main.go          # Go WebAssembly代码
├── main.wasm        # 编译后的WebAssembly
├── wasm_exec.js     # Go运行时支持
└── index.html       # 前端页面

这个示例展示了Go WebAssembly的核心用法,包括函数导出、数据传递、异步操作和性能优化策略。

回到顶部