我用Go语言创建了一个测试WASM程序。在程序的main中,它为"全局"添加了一个API,并等待一个通道以避免退出。它类似于典型的hello世界Go WASM,你可以在互联网上的任何地方找到。
我的测试WASM程序在浏览器中运行良好,不过,我希望运行它并使用Node.js调用API。如果可能的话,我将基于它创建一些自动化测试。
我尝试了很多方法,但我就是不能让它在Node.js中工作。问题是,在Node.js中,API无法在"全局"中找到。我如何在Node.js中运行GO WASM程序(带有导出的API)?
(Let我知道如果你需要更多的细节)
谢谢!
更多详情:
- --Go那边(伪代码)---
func main() {
fmt.Println("My Web Assembly")
js.Global().Set("myEcho", myEcho())
<-make(chan bool)
}
func myEcho() js.Func {
return js.FuncOf(func(this js.Value, apiArgs []js.Value) any {
for arg := range(apiArgs) {
fmt.Println(arg.String())
}
}
}
// build: GOOS=js GOARCH=wasm go build -o myecho.wasm path/to/the/package
- --在浏览器端---
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<p><pre style="font-family:courier;" id="my-canvas"/></p>
<script src="wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch("myecho.wasm"), go.importObject).then((result) => {
go.run(result.instance);
}).then(_ => {
// it also works without "window."
document.getElementById("my-canvas").innerHTML = window.myEcho("hello", "ahoj", "ciao");
})
})
</script>
</body>
</html>
- --在Node.js端---
globalThis.require = require;
globalThis.fs = require("fs");
globalThis.TextEncoder = require("util").TextEncoder;
globalThis.TextDecoder = require("util").TextDecoder;
globalThis.performance = {
now() {
const [sec, nsec] = process.hrtime();
return sec * 1000 + nsec / 1000000;
},
};
const crypto = require("crypto");
globalThis.crypto = {
getRandomValues(b) {
crypto.randomFillSync(b);
},
};
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;
WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => {
go.run(result.instance);
}).then(_ => {
console.log(go.exports.myEcho("hello", "ahoj", "ciao"));
}).catch((err) => {
console.error(err);
process.exit(1);
});
这个伪代码代表了我真实代码的99%内容(只删除了业务相关的细节)。问题是我不仅需要运行WASM程序(myecho.wasm),但我还需要调用"api"(myEcho),我需要向它传递参数并接收返回值,因为我想为这些"api"创建自动化测试。我可以在命令行环境中启动测试js脚本并验证输出结果,浏览器对这种情况来说不是一个方便的工具。
用node wasm_exec.js myecho.wasm
运行程序不足以解决我的问题。
2条答案
按热度按时间eyh26e7m1#
如果能知道更多关于你的环境的细节以及你实际上想做什么,那就太好了。你可以发布代码本身、编译命令和所有涉及到的工具的版本。
尝试回答问题而不考虑这些细节:
Go WASM非常面向浏览器,因为Go编译器需要wasm_exec.js中的glue js来运行。Nodejs应该不会有问题,下面的command应该可以工作:
其中
wasm_exec.js
是go
发行版附带的粘合代码,通常可以在$(go env GOROOT)/misc/wasm/wasm_exec.js
中找到,main.wasm
是您的编译代码。如果失败,您也可以发布输出。还有一种方法可以绕过
wasm_exec.js
将go代码编译成wasm,那就是使用TinyGo编译器输出支持wasi的代码,你可以尝试按照他们的指导编译你的代码。对于example:
您可以为example构建一个javascript文件
wasi.js
:最新版本的
node
具有实验性的wasi
支持:这些通常都是您在Go语言和WASM中尝试的东西,但是如果没有进一步的细节,很难说到底是什么不起作用。
jhiyze9q2#
经过一番挣扎,我注意到原因比我想象的要简单。
我无法在Node.js中获取导出的API函数,原因很简单,当我试图调用它们时,API尚未导出!
当加载并启动wasm程序时,它与调用程序(在Node中运行的js)并行运行。
WebAssembly.instantiate(...).then(...go.run(result.instance)...).then(/*HERE!*/)
“HERE”处的代码执行过早,wasm程序的
main()
尚未完成API导出。当我将Node脚本更改为以下内容时,它工作正常:
(only包括变更部分)
我知道这似乎不是一个完美的解决方案,但至少它证明了我对根本原因的猜测是正确的。
但是...为什么它没有发生在浏览器?* 叹息... *