哈啰!WebAssembly!


Go 1.11 实验性地加入了 WebAssembly 的支持,这表示你可以使用 Go 来编写代码,然后令其在网页中执行,也可以与浏览器互动,像是浏览器的 JavaScript 环境、DOM 操作等。

对 Go 开发者而言,理想的状况下,若 Go 封装的好,最好是可以完全忽略 JavaScript、浏览器环境等事实,也不需要知道 WebAssembly 的细节,然而,毕竟目前还是实验性质,如果能认识 JavaScript、浏览器、WebAssembly 的特性,对使用 Go 编写程序并编译为 WebAssembly 来说,是有很大的帮助的。

如果对 JavaScript、浏览器的细节有兴趣,建议参考〈ECMAScript 本质部份〉,如果对 WebAssembly 的细节有兴趣,建议参考〈WebAssembly〉文件。

无论如何,来看个简单的 Go 程序如何编译为 WebAssembly,首先,来个简单的 Go 程序:

package main

func main() {
    println("Hello, WebAssembly")
}

再简单也不过,在编译为 WebAssembly 之后,println的输出默认会是浏览器控制台(console),接下来,若要编译为 WebAssembly,环境变量GOOS必须设定为jsGOARCH必须设定为wasm

如果你是使用 Visual Studio Code,安装了vscode-go扩充,可以在 settings.json 中设定:

{
    "go.toolsEnvVars": {"GOOS":"js", "GOARCH": "wasm"}
}

如果是要在 Visual Studio Code 开启的终端中设定环境变量,因为它是基于 Power Shell,可以如下设定环境变量:

$env:GOOS="js"
$env:GOARCH="wasm"

如果是在 Windows 的命令提示字符,就是使用set了:

SET GOOS=js
SET GOARCH=wasm

接下来,可以执行构造:

go build -o test.wasm main.go

test.wasm 是编译出来的 WebAssembly 模块字节码,除了你编写的程序之外,根据〈Go 1.11 Release Notes〉,编译出来的 WebAssembly 模块也包含了 goroutine、垃圾收集、maps 等功能的执行环境,最小约在 2MB 左右,压缩后可以减至 500KB。

接下来就是开个 HTML 文件,在当中使用 JavaScript,运用 Fetch API、WebAssembly API 等,获取、编译、初始化化 WebAssembly 模块,这些细节在〈WebAssembly〉文件都有谈到。

如果想要直接有个现成的加载页面可以使用,可以复制 Go 安装目录的 misc\wasm 中 wasm_exec.html 与 wasm_exec.js 到你的工作目录之中,wasm_exec.html 里头写的 JavaScript,会使用 Fetch API 来获取 test.wasm,这也是为什么,方才编译时指定输出文件名称为 test.wasm 的原因。

如果你有安装 Node.js,那么可以直接搭配 wasm_exec.js 来运行 test.wasm,这会显示 Hello, WebAssembly:

node wasm_exec.js test.wasm

如果要在浏览器中运行,你需要有个 HTTP 服务器,例如 Node.js 的http-server,在启动之后,请求你的 http://localhost:8080/wasm_exec.html。

这会看到一个 Run 按钮,开启你浏览器上的开发者工具,然后按下网页中的 Run 按钮,你就会看到开发者工具中的控制台显示了文本:

哈啰!WebAssembly!

要注意的是,在执行完 Go 的main之后,程序就结束了,就网页中 Run 按钮的事件来说,每按一次是会重新跑一次 WebAssembly 模块实例,也就是重新跑一次main流程,有时这不会是你想要的,这时就要在 Go 中以某种方式,阻断main的流程,这之后还会看到。

这只是个体验,之后的文件还会谈到,如何操作浏览器中的 JavaScript、DOM,以及 Go 中定义的函数,如何能被 JavaScript 获取调用。


展开阅读全文