使用Golang和WebAssembly进行客户端Web开发
使用Golang和WebAssembly进行客户端Web开发 大家好,
我注意到关于 Go 1.11 中新增的 WebAssembly 支持的讨论还不多,因此决定亲自尝试并探索其功能。在使用过程中收获了不少乐趣,现在想分享一些代码来鼓励其他 Go 程序员开始使用 WebAssembly。
Go 在服务端网页编程领域广受欢迎,而现在它也能在客户端发挥作用。
以下是我创建的一个小型 Go WebAssembly 应用:http://jayts.com/vp/
这个程序完全使用 Go 编写,没有写一行 JavaScript!(虽然需要 JavaScript 胶水代码来加载应用,但这部分直接复制自 $GOHOME/misc/wasm。)
代码仓库在这里:https://github.com/Yaoir/VideoPoker-Go-WebAssembly
README 文件包含了游戏操作说明。HTML、CSS 和 Go 代码均附有注释,方便理解 WebAssembly 的工作原理。如果你想尝试创建自己的 WebAssembly 应用,这份代码可以作为起点。我还准备了一个更简单的 Go WebAssembly 示例,可能更适合入门学习:https://github.com/Yaoir/ClockExample-Go-WebAssembly
希望使用 Mac 和 iOS 设备的用户能通过 Safari、Firefox、Chrome 和 Opera 浏览器测试视频扑克应用在苹果产品上的运行效果。目前唯一发现的问题是在安卓 4.2 平板的 Firefox 浏览器上存在兼容性。总体而言,WebAssembly 的兼容性表现良好。
更多关于使用Golang和WebAssembly进行客户端Web开发的实战教程也可以访问 https://www.itying.com/category-94-b0.html
jayts: 我想听听Mac的看法
Safari仍在加载中。但Chrome可以正常工作… 😊
更多关于使用Golang和WebAssembly进行客户端Web开发的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
嗨 Jay,
自从看到 Go 1.11 更新后,我就想尝试一下 Web Assembly。感谢你提供的代码!
将 Opera 添加到支持列表中,刚刚在 macOS 10.13.6 上进行了测试。如果对大家有帮助的话,在 Linux Mint 19 的 Opera 浏览器上也能正常运行。
以下部分将解决关于管理和客户端网页开发的认知问题,这些问题与WebAssembly相关,因此在Chrome中可以正常工作,但有时会卡在加载状态。
在使用三星Plus(arm64)上的Chrome OS Crostini时: 时钟示例运行正常,但视频扑克游戏在"游戏正在加载"处卡住了。
// 代码示例保留原样
在 Chrome、Firefox 和 Safari 浏览器中,该功能在 macOS 10.14.1(最新版本)上运行正常。我可以在周日测试 iOS 版本。做得不错!唯一注意到的区别是在 Chrome 版本中我获胜的次数更多了。
也许你的浏览器缓存在这里跟你开了个玩笑?你可以通过添加未使用的查询参数来引用wasm文件,比如使用修改时间作为参数。例如 myprogram.wasm?t=78888776,这样新版本就会始终被加载,而不会被浏览器使用缓存版本。如果你无法自动修改js文件或HTML文件,是否可以考虑在URL中显式更改版本号?例如使用 myprogram.wasm?version=1.0.1,并在每次更新wasm时修改这个版本号。
感谢大家的帮助测试!很高兴知道在Mac上运行正常。希望它在iOS上也能同样顺利运行。
我在HTML文件中尝试了不同的JavaScript粘合代码,但在Android的Firefox上仍然遇到同样的问题。我想知道这个问题是否特定于我使用的旧版Android,还是也会影响更新的Android版本。
希望能获得更多关于这方面的测试帮助,这样我就能确定是否需要将其作为Go/wasm或Firefox的bug进行上报。(要帮忙的话,请在Android上启动Firefox并运行该应用,然后重新加载页面。这个bug的表现是应用永远无法完成加载。清除浏览器缓存可以修复这个问题。有时,快速多次点击重新加载按钮也能解决。)
如果有专家看到这里,问题的关键在于JavaScript粘合代码在WebAssembly.instantiateStreaming()调用处卡住了。
// 代码示例保留原文
以下是针对您分享的Go WebAssembly项目的专业评论,重点分析技术实现并提供示例代码:
技术实现分析
- WebAssembly编译流程:
# 设置目标平台为wasm
GOOS=js GOARCH=wasm go build -o main.wasm main.go
需要配套使用wasm_exec.js加载器,该文件位于$GOROOT/misc/wasm/目录。
- DOM操作示例:
package main
import (
"syscall/js"
)
func main() {
doc := js.Global().Get("document")
body := doc.Call("getElementById", "app")
// 创建按钮元素
btn := doc.Call("createElement", "button")
btn.Set("innerHTML", "Go WASM Button")
btn.Call("addEventListener", "click", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
js.Global().Get("console").Call("log", "Button clicked from Go!")
return nil
}))
body.Call("appendChild", btn)
// 保持Go程序运行
select {}
}
- 性能优化建议:
- 使用
js.Func包装Go函数时注意内存管理 - 通过
js.GC()主动触发垃圾回收 - 避免频繁的Go-WASM边界数据交换
兼容性处理
针对您提到的Android 4.2兼容性问题,可添加特征检测:
// 检测WebAssembly支持
if js.Global().Get("WebAssembly").IsUndefined() {
js.Global().Get("console").Call("warn", "WebAssembly not supported")
return
}
构建配置示例
// go:build js && wasm
// +build js,wasm
package main
import "syscall/js"
func registerCallbacks() {
js.Global().Set("goFunc", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
// 处理逻辑
return nil
}))
}
您的项目展示了Go在客户端开发的可行性,特别是完整的游戏实现证明了WASM的成熟度。视频扑克的DOM操作和事件处理实现为同类项目提供了重要参考。



