Administrator
Administrator
发布于 2026-02-01 / 12 阅读
0
0

golang编绎wasm和浏览器、NodeJS中运行wasm

golang编绎wasm

首先改变编绎目标

go env -w GOOS=js GOARCH=wasm

(如果用的是goland)再到IDE中修改配置

简易代码

由于syscall/js是实验性的,所以需要在第一行加上//go:build js && wasm

//go:build js && wasm

package main

import (
	"syscall/js"
)

func main() {
	window := js.Global()
	window.Set("goAdd", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		return args[0].Int() + args[1].Int()
	}))
	select {}
}

编绎

go build -o main.wasm main.go

得到wasm文件

运行编绎的wasm

所需的胶水层(wasm_exec.js)文件在:$GOROOT$/lib/wasm

将编绎的wasm文件和wasm_exec.js拷贝到一个目录中

浏览器中运行

新建一个html文件写如下代码(和wasm文件、wasm_exec.js放在一起)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./wasm_exec.js"></script>
</head>
<body>
    
</body>
<script>
    var go = new Go();
    WebAssembly.instantiateStreaming(fetch('./main.wasm'), go.importObject).then(obj => {
        console.log(obj.instance.exports);
        go.run(obj.instance);
        
        //从这里开始就可以调用wasm导出的函数了,例如在简易代码中的goAdd函数
        console.log(goAdd(10,20));
    });
</script>
</html>

NodeJS中运行

新建一个js文件写如下代码(和wasm文件、wasm_exec.js放在一起)

// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

"use strict";

globalThis.require = require;
globalThis.fs = require("fs");
globalThis.path = require("path");
globalThis.TextEncoder = require("util").TextEncoder;
globalThis.TextDecoder = require("util").TextDecoder;

globalThis.performance ??= require("performance");

globalThis.crypto ??= require("crypto");

require("./wasm_exec");

const go = new Go();

// go.argv = process.argv.slice(2);
// go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env);
go.exit = process.exit;
var bytes = fs.readFileSync(path.join("main.wasm"))

WebAssembly.instantiate(bytes, go.importObject).then((result) => {
	process.on("exit", (code) => { // Node.js exits if no event handler is pending
		if (code === 0 && !go.exited) {
			// deadlock, make Go print error and stack traces
			go._pendingEvent = { id: 0 };
			go._resume();
		}
	});
    go.run(result.instance);

    console.log(goAdd(10,20));
    
}).catch((err) => {
	console.error(err,11);
	process.exit(1);
});

console.log(typeof sign);

运行第三方网站平台的wasm

拿一个别人网站来示例,用的是golang编绎的,网址:aHR0cHM6Ly93d3cud2FpbWFveGlhLm5ldC8=

网页加载时会有这二个文件,下载到本地。(最好用第三方平台提供的wasm_exec,如果用golang的lib目录下的可能有问题)

(在go.run之后所有wasm编绎时指定开放的函数都会成为全局函数,在window或globalThis下)

在浏览器中运行

新建一个html文件,写入如下代码,将main.wasm和wasm_exec_v2.js放到与html相同位置

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./wasm_exec_v2.js"></script>
</head>
<body>
    
</body>
<script>
    var go = new Go();
    WebAssembly.instantiateStreaming(fetch('./main.wasm'), go.importObject).then(obj => {
        console.log(obj.instance.exports);
        go.run(obj.instance);
        
        //从这里开始就可以调用wasm导出的函数了,例如该网站中的sign()
        console.log(sign("11","22","33","","",""));
    });
</script>
</html>

Node.JS中运行

// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

"use strict";

globalThis.require = require;
globalThis.fs = require("fs");
globalThis.path = require("path");
globalThis.TextEncoder = require("util").TextEncoder;
globalThis.TextDecoder = require("util").TextDecoder;

globalThis.performance ??= require("performance");

globalThis.crypto ??= require("crypto");

require("./wasm_exec_v2");

const go = new Go();
go.exit = process.exit;
var bytes = fs.readFileSync(path.join("main.wasm"))

WebAssembly.instantiate(bytes, go.importObject).then((result) => {
	process.on("exit", (code) => {
		if (code === 0 && !go.exited) {
			go._pendingEvent = { id: 0 };
			go._resume();
		}
	});
    go.run(result.instance);

    console.log(sign("11","22","33","","","")); //调用方法
  
}).catch((err) => {
	console.error(err,11);
	process.exit(1);
});

附言

每个由golang定义的函数在前端导航过去都长这样

function () {
	const event = { id: id, this: this, args: arguments };
	go._pendingEvent = event;
	go._resume();
	return event.result;
};


评论