使用加1项目体验golang的wasm

2018/06/20

什么是WebAssembly

WebAssembly(以下简称wasm)是一种新的编码方式,可以在现代的网络浏览器中运行。啥意思,就是除了JavaScript(以下简称js),还有一种语言可以在浏览器里面运行了!

对于网络平台而言,WebAssembly具有巨大的意义——它提供了一条途径,以使得以各种语言编写的代码都可以以接近原生的速度在Web中运行。在这种情况下,以前无法以此方式运行的客户端软件都将可以运行在Web中。

编译支持wasm的go

golang的release版本(1.10)还不支持wasm,但是在github.com/golang/go的master分支中已经包含wasm了,所以我们需要自己编译一个go。

git clone http://github.com/golang/go /path/go
cd /path/go/src
./make.bash

/path/go/bin/目录下会生成编译后的go:/path/go/bin/go

设置GOROOT/path/go/

创建自己的wasm程序

参见项目:https://github.com/Chyroc/golang-wasm-example

index.html

index.html引入了wasm_exec.js(这个是从/path/go/misc/wasm/wasm_exec.js复制来过的)和加载wasm的js(这个参见参见文档),总之这样我们的wasm就已经加载到我们的网页了

最后有一个显示数字的span块,和两个+-的button,我们待会写的wasm代码就是操作这个span块的

<html>
<head>
    <title>加1减1</title>
    <script src="wasm_exec.js"></script>
    <script type="text/javascript">
        function fetchAndInstantiate(url, importObject) {
            return fetch(url).then(response =>
                    response.arrayBuffer()
            ).then(bytes =>
                    WebAssembly.instantiate(bytes, importObject)
            ).then(results =>
                    results.instance
            );
        }

        var go = new Go();
        var mod = fetchAndInstantiate("./example.wasm", go.importObject);
        window.onload = function () {
            mod.then(function (instance) {
                go.run(instance);
            });
        };
    </script>
</head>
<body>
<br>
<div>加1减1</div>
<br>
<button id="minus" type="button" disabled=true>-</button>
<span id="number">0</span>
<button id="plus" type="button" disabled=true>+</button>
</body>
</html>

wasm.go

第一行有build tag:// +build js,wasm表示GOARCHwasmGOOSjs

然后syscall/js包提供了操作网页的接口:

js.Global.Get("document").Call("getElementById", "number")这几行获取到刚刚index.html中最后一个按钮和span块

全局变量number是我们最后操作的数字

然后对+-按钮添加事件监听,监听到按了+,就将number加1;监听到按了-,就将number减1;并渲染span块。

plus.Set("disabled", false)这两句会在页面wasm加载后将+-按钮disable状态去掉,变成可点击状态

最后使用select{}阻塞go程序不退出

// +build js,wasm

package main

import (
	"syscall/js"
	"strconv"
)

func main() {
	var numberDoc = js.Global.Get("document").Call("getElementById", "number")
	var plus = js.Global.Get("document").Call("getElementById", "plus")
	var minus = js.Global.Get("document").Call("getElementById", "minus")
	var number int

	plus.Call("addEventListener", "click", js.NewCallback(func(args []js.Value) {
		println("press +")
		number++
		numberDoc.Set("innerHTML", strconv.Itoa(number))
	}))

	minus.Call("addEventListener", "click", js.NewCallback(func(args []js.Value) {
		number--
		numberDoc.Set("innerHTML", strconv.Itoa(number))
		println("press -")
	}))

	plus.Set("disabled", false)
	minus.Set("disabled", false)

	select {}
}

程序效果请访问:https://blog.chyroc.cn/golang-wasm-example/ 体验

参考