Go WebAssembly 实践
Contents
Go-WebAssembly实践
在网页端实现一个json转struct
Hello Word
-
创建项目目录
1 2 3 4 5 6Documents/ └── webassembly ├── assets └── cmd ├── server └── wasm -
在 webassembly初始化go项目
1go mod init teswebassembly -
在
webassembly/cmd/wasm下创建main.go1 2 3 4 5 6 7 8 9package main import ( "fmt" ) func main() { fmt.Println("Go Web Assembly") } -
编译
1 2cd webassembly/cmd/wasm/ GOOS=js GOARCH=wasm go build -o ../../assets/json.wasm生成了在浏览器中运行的二进制文件
-
获取
wasm_exec.js用来调用json.wasm1cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" webassembly/assets/ -
在
webassembly/cmd/wasm下创建index.html1 2 3 4 5 6 7 8 9 10 11 12 13<html> <head> <meta charset="utf-8"/> <script src="wasm_exec.js"></script> <script> const go = new Go(); WebAssembly.instantiateStreaming(fetch("json.wasm"), go.importObject).then((result) => { go.run(result.instance); }); </script> </head> <body></body> </html> -
目前目录
1 2 3 4 5 6 7 8 9 10 11Documents/ └── webassembly ├── assets │ ├── index.html │ ├── json.wasm │ └── wasm_exec.js └── cmd ├── server └── wasm └── main.go └── go.mod -
做一个简单服务器用来运行
index.html,编译器自带也可以在
webassembly/cmd/server下创建main.go1 2 3 4 5 6 7 8 9 10 11 12 13 14package main import ( "fmt" "net/http" ) func main() { err := http.ListenAndServe(":8080", http.FileServer(http.Dir("../../assets"))) if err != nil { fmt.Println("Failed to start server", err) return } } -
运行
1 2cd webassembly/cmd/server/ go run main.go
在控制台中可以看到打印
功能实现
Json2Go 使用的是 github.com/m-zajac/json2go
在webassembly/cmd/wasm/main.go中添加
-
添加功能代码
1 2 3 4 5 6 7 8 9 10import ( "github.com/m-zajac/json2go" ) func Json2Go(input string) string { parser := json2go.NewJSONParser("Document") parser.FeedBytes([]byte(input)) res := parser.String() return res } -
将函数暴露到
Javascript1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22import ( "syscall/js" ) func main() { fmt.Println("Go Web Assembly") js.Global().Set("json2Go", Json2GoWrapper()) //避免 Error: Go program has already exited <-make(chan bool) } func Json2GoWrapper() js.Func { jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) any { if len(args) != 1 { return "Invalid no of arguments passed" } inputJSON := args[0].String() res := Json2Go(inputJSON) return res }) return jsonFunc }syscall/js编译器报错设置
-
编写ui
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22<html> <head> <meta charset="utf-8"/> <script src="wasm_exec.js"></script> <script> const go = new Go(); WebAssembly.instantiateStreaming(fetch("json.wasm"), go.importObject).then((result) => { go.run(result.instance); }); </script> </head> <body> <textarea id="jsoninput" name="jsoninput" cols="80" rows="20"></textarea> <input id="button" type="submit" name="button" value="pretty json" onclick="json(jsoninput.value)"/> <textarea id="jsonoutput" name="jsonoutput" cols="80" rows="20"></textarea> </body> <script> var json = function (input) { jsonoutput.value = json2Go(input) } </script> </html> -
测试

DOM操作
-
修改
webassembly/cmd/wasm/main.go中Json2GoWrapper方法1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29func Json2GoWrapper() js.Func { jsonfunc := js.FuncOf(func(this js.Value, args []js.Value) any { if len(args) != 1 { result := map[string]any{ "error": "Invalid no of arguments passed", } return result } jsDoc := js.Global().Get("document") if !jsDoc.Truthy() { result := map[string]any{ "error": "Invalid no of arguments passed", } return result } jsonOuputTextArea := jsDoc.Call("getElementById", "jsonoutput") if !jsonOuputTextArea.Truthy() { result := map[string]any{ "error": "Invalid no of arguments passed", } return result } inputJSON := args[0].String() res := Json2Go(inputJSON) jsonOuputTextArea.Set("value", res) return nil }) return jsonfunc } -
修改
webassembly/assets/index.html1 2 3 4 5 6 7 8 9 10 11<script> var json = function (input) { var result = json2Go(input) if (( result != null) && ('error' in result)) { console.log("Go return value", result) jsonoutput.value = "" alert(result.error) } // jsonoutput.value = json2Go(input) } </script>
错误处理
由于js无法处理error类型,对应表:https://pkg.go.dev/syscall/js#ValueOf

所以错误处理返回map[string]interface{}
|
|
Json参数传递
-
index.html1 2 3 4 5<script> var json = function (input) { jsonoutput.value = json2Go({"json": input}) } </script> -
Go接收
1 2 3 4 5 6 7 8 9 10 11func Json2GoWrapper() js.Func { jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) any { if len(args) != 1 { return "Invalid no of arguments passed" } inputJSON := args[0].Get("json").String() res := Json2Go(inputJSON) return res }) return jsonFunc }
第二大脑

