开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情
最近学习了Wasm,吸收了很多知识,因此做一个记录和大家分享
文章大纲:
一、前言
随着 Web 应用的不断发展,越来越多的开发者开始使用 Go 和 Wasm 来构建高效、安全的 Web 应用。本文的目的是帮助读者快速了解 Go 和 Wasm 的基本概念和实战技巧,使其能够快速上手 Go 和 Wasm 开发。
1.1 本文代码开发环境
系统:Windows 11 22H2
IDE:VSCode、GoLand
1.2 基本概念
为了更好的帮助读者理解Wasm,这里给出一些相关的定义
Wasm (WebAssembly) 是一种运行在 Web 浏览器上的高效、安全的编程语言,旨在为 Web 应用提供一个更快、更安全、更灵活的运行环境。Wasm 通过提供二进制的格式和相关的 API,使得开发者能够在 Web 浏览器上运行 C/C++ 等语言编写的代码,从而实现更快、更高效的 Web 应用。
Wasm 的优势在于:
- 性能:Wasm 代码在 Web 浏览器上运行速度比 JavaScript 快得多,这使得开发者能够在 Web 浏览器上实现更复杂、更多功能的应用。
- 安全:Wasm 代码运行在沙箱环境中,从而保证了应用的安全性。
- 可移植性:Wasm 代码是二进制的,可以在任何支持 Wasm 的平台上运行,从而实现代码的可移植性。
- 灵活性:Wasm 支持多种语言的编写,包括 C/C++、Rust、Go 等,这使得开发者能够使用自己熟悉的语言编写 Web 应用。
在现实中,Wasm 已经被广泛应用在游戏开发、虚拟和增强现实等领域,并且有越来越多的 Web 开发者开始使用 Wasm 进行实际项目的开发。
于是,简单来说,Wasm是一种高效的Web编程语言。
二、开发环境搭建
2.1 安装 Go 和 Wasm 工具链
- 安装 Go:Go 官方网站提供了详细的安装说明,包括 Windows、macOS 和 Linux 系统的安装方法。请访问 golang.org/dl 获取安装说明。
输入以下命令,正确输出版本号则安装成功
go version
- 安装并配置 TinyGo。TinyGo是一个编译 Go 代码为 WebAssembly 的工具,其官方网站提供了详细的安装说明,包括 Windows、macOS 和 Linux 系统的安装方法。请访问 Quick install guide | TinyGo 获取安装说明。
输入以下命令,正确输出版本号则安装成功
tinygo version
2.2 编译 Wasm模块
- 编写 Go 代码并使用 TinyGo 编译为 Wasm 二进制文件。
main.go:
package main
func main() {
println("Hello world!")
}
使用 TinyGo 编译:
tinygo build -o ./wasm.wasm -target wasm .\main.go
没有意外的话这里会报错:
error: could not find wasm-opt, set the WASMOPT environment variable to override
wasm-opt 是 WebAssembly 的优化器,TinyGo 可以使用它来优化生成的 Wasm 代码。报错提示没有wasm-opt,因为最新版本已经更换,原因如下:Windows release missing wasm-opt.exe · Issue #2601 · tinygo-org/tinygo (github.com)
解决方法直接下载
WebAssembly/binaryen: Optimizer and compiler/toolchain library for WebAssembly (github.com)
设置环境变量重启你的终端和IDE,重新编译即可
三、介绍 Wasmer 库
3.1 Wasmer简介
Wasmer 是一个高性能的 WebAssembly(Wasm)运行时。它支持多种语言(如 Rust、C、C++、Go、JavaScript 等)编写的 WebAssembly 模块运行在各种环境(如浏览器、服务器、命令行)中。
Wasmer 的优点在于:
- 它提供了高效的加载和执行速度,比传统的 JavaScript 快数十倍以上。
- 它可以在不同环境中(例如,浏览器、服务器、命令行)中使用,并且它的 API 是统一的,无需考虑不同环境的差异。
- 它支持多种语言(如 Rust、C、C++、Go、JavaScript 等)编写的 WebAssembly 模块,并且可以在不同语言间实现更高效的交互。
使用 Wasmer 库需要先安装相应的工具(例如,Rust、JavaScript),然后通过相应工具的包管理工具(例如,npm)安装 Wasmer 库。具体示例代码请参考 Wasmer 库的官方文档。
3.2Wasmer 使用
Wasmer用法有很多,我用的最多的一个参数是run,它允许我们在使用wasmer运行时,去执行已经编译好的产物。
以前文编译好的main.wasm为例,在main.wasm目录下打开终端,执行以下命令:
wasmer run main.wasm
执行结果如下:
至于wasmer其他的用法,我暂时还没有用到,等以后用到了我会回来更新这部分内容。
四、一个简单的🌰
4.1 Hello World
首先创建main.go:
//+build wasm,js
package main
import (
"fmt"
"time"
)
func exampleFunc() {
num := 0
for {
fmt.Println("Hello from Web Assembly. Number of times this goroutine has ran: ", num)
time.Sleep(1 * time.Second)
num++
}
}
func main() {
// This exitChan blocks the program from returning the main function.
// Without it, your program will exit before the goroutine can complete its execution.
// This is useful if you want your goroutines to continually run.
exitChan := make(chan string)
go exampleFunc()
<-exitChan
}
然后创建index.html:
<html>
<title>Web Assembly Work</title>
<head>
<meta charset="utf-8">
<script src="wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => {
go.run(result.instance);
});
</script>
</head>
<body>
<div id="main">
<center>
Check the javascript console output of your browser to ensure execution.
</center>
</div>
</body>
</html>
同时将wasm_exec.js从官方包复制到项目中来
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
创建http-server,编写一个简单的服务器:
// A basic HTTP server.
// By default, it serves the current working directory on port 12000.
package main
import (
"flag"
"log"
"net/http"
)
var (
listen = flag.String("listen", ":12000", "listen address")
dir = flag.String("dir", "./public", "directory to serve")
)
func main() {
flag.Parse()
log.Printf("listening on %q...", *listen)
err := http.ListenAndServe(*listen, http.FileServer(http.Dir(*dir)))
log.Fatalln(err)
}
整理代码:
使用 TinyGo 编译:
tinygo build -o public/main.wasm -target wasm .\main.go
启动内置服务器:
go run utilities/http-server.go
打开浏览器,访问localhost:12000/index.html,检查F12控制台:
4.2 技巧和注意事项:
- 注意性能:Wasm 可能不如本地代码快,因此需要仔细监控代码的性能,并对其进行优化。
- 注意浏览器兼容性:Wasm 目前在所有主流浏览器中都受到支持,但是在一些旧版本的浏览器中可能不受支持。因此,在使用 Wasm 时需要注意浏览器兼容性。(特别吐槽一句:我在写这篇文章的时候用Edge做的测试,代码运行一直有错,调试半天没看出啥问题,后来换了火狐运行正常了……,总之避坑Edge)
- 选择合适的库:Go 和 Wasm 中有很多可用的库,但由于开发环境不同,有的不支持Windows或者支持度不高,因此需要根据项目的需求选择合适的库。(嘛,虽然WSL2也挺方便的)
- 调试:在使用 Wasm 时,调试可能会变得更加困难,因此需要使用合适的调试工具来帮助解决问题。(我个人推荐
GoLand,真的超好用!!!)
五、最后
5.1 总结
本文介绍了WebAssembly的一些基本概念,和WebAssembly开发环境的搭建,使用Go和Wasm在控制台打印属于WebAssembly的Hello World,读者可以根据本文的步骤,自行实现这个小例子。
5.2 参考资料
- Go官方文档:golang.org/doc/
- Wasm官方网站:webassembly.org/docs/
- 通过例子学wasm:wasmbyexample.dev/examples/he…