WebAssembly

02 JS WASM 阅读更多

JavaScript 对象是所有 WebAssembly 相关功能的命名空间。 和大多数全局对象不一样,WebAssembly不是一个构造函数(它不是一个函数对象)。它类似于 Math 对象或者 Intl 对象: Math(也是一个命名空间对象):用于保存数学常量和函数 Intl:用于国际化和其他语言相关函数的命名空间对象 描述 WebAssembly对象主要用于: 使用 WebAssembly.instantiate() 函数加载 WebAssembly 代码 通过 WebAssembly.Memory()或WebAssembly.Table()构造函数创建新的内存和表实例 由WebAssembly.CompileError()或WebAssembly.LinkError()或WebAssembly.RuntimeError()构造函数来提供 WebAssembly 中的错误信息 方法 方法名 用途 WebAssembly.instantiate() 用于编译和实例化 WebAssembly 代码的主 API,返回一个 Module 和它的第一个Instance实例 WebAssembly.instantiateStreaming() 直接从流式底层源编译和实例化WebAssembly模块,同时返回Module及其第一个Instance实例 WebAssembly.compile() 把 WebAssembly 二进制代码编译为一个 WebAssembly.Module ,不进行实例化 WebAssembly.compileStreaming() 直接从流式底层源代码编译 WebAssembly.Module ,将实例化作为一个单独的步骤 WebAssembly.validate() 校验 WebAssembly 二进制代码的类型数组是否合法,合法则返回 true ,否则返回 false 构造器 构造器 描述 WebAssembly.Global() 创建一个新的 WebAssembly Global 全局对象 WebAssembly.Module() 创建一个新的 WebAssembly Module 模块对象 WebAssembly.Instance() 创建一个新的 WebAssembly Instance 实例对象 WebAssembly.Memory() 创建一个新的 WebAssembly Memory 内存对象 WebAssembly.Table() 创建一个新的 WebAssembly Table 表格对象 WebAssembly.CompileError() 创建一个新的 WebAssembly CompileError 编译错误对象 WebAssembly.LinkError() 创建一个新的 WebAssembly LinkError 链接错误对象 WebAssembly.RuntimeError() 创建一个新的 WebAssembly RuntimeError 运行时错误对象 示例 var importObject = { imports: { imported_func: arg => console.log(arg) } }; WebAssembly.instantiateStreaming(fetch('simple.wasm'), importObject).then(obj => obj.instance.exports.exported_func()) 上面例子,直接从流式底层源传输.wasm模块,然后对其进行编译和实例化,并通过ResultObject实现promise。 由于instantiateStreaming()函数接受对 Response 对象的 promise,因此可以直接向其传递WindowOrWorkerGlobalScope.fetch()调用,然后它将把返回的response传递给随后的函数。 返回的ResultObject实例的成员可以被随后访问到,可以调用实例中被导出的方法。

01-WebAssembly 阅读更多

简介 Go 1.11向WebAssembly添加了一个实验端口。 Go 1.12对它的某些部分进行了改进,并有望在Go 1.13中进行进一步的改进。 WebAssembly在其主页上描述为: WebAssembly(缩写为Wasm)是基于堆栈的虚拟机的二进制指令格式。 Wasm被设计为可移植目标,用于编译高级语言(如C/C++/Rust),从而可以在Web上为客户端和服务器应用程序进行部署。 如果不熟悉WebAssembly,请阅读下面的“入门”部分,观看下面的一些“Go WebAssembly讲座”,然后查看下面的更多“示例”。 入门 此页面假定Go 1.11或更高版本可以正常运行。有关故障排除,请参阅“安装故障排除”页面。 为Web编译一个基本的Go语言包: package main import "fmt" func main() { fmt.Println("Hello, WebAssembly!") } 设置环境变量GOOS=js和GOARCH=wasm来针对WebAssembly进行编译: GOOS=js GOARCH=wasm go build -o main.wasm 这将生成程序包并生成一个名为main.wasm的可执行WebAssembly模块文件。.wasm文件扩展名将使以后通过带有正确的Content-Type标头的HTTP服务更加容易。 请注意,只能编译主软件包。否则,将获得无法在WebAssembly中运行的目标文件。如果具有要与WebAssembly一起使用的软件包,请将其转换为主软件包并生成二进制文件。 要在浏览器中执行main.wasm,我们还需要一个JavaScript支持文件和一个HTML页面来将所有内容连接在一起。 复制JavaScript支持文件: cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" . 新建一个index.html文件: <html> <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></body> </html> 如果浏览器尚不支持WebAssembly.instantiateStreaming,则可以使用polyfill。 然后从Web服务器提供三个文件(index.html、wasm_exec.js、main.wasm)。例如使用goexec: # install goexec: go get -u github.com/shurcooL/goexec goexec 'http.ListenAndServe(`:8080`, http.FileServer(http.Dir(`.`)))' 或者使用基本的HTTP服务器命令。 将/usr/local/go/bin添加到PATH环境变量中。可以通过将以下行添加到/etc/profile(用于系统范围的安装)或$HOME/ .profile中来完成此操作: export PATH=$PATH:/usr/local/go/bin 注意:对配置文件的更改可能要等到下一次登录计算机后才能应用,或者执行source命令。 最后,浏览至http//localhost:8080/index.html,打开JavaScript调试控制台,应该会看到输出。可以修改程序,重建main.wasm,然后刷新以查看新的输出。 使用Node.js执行WebAssembly 可以使用Node.js而非浏览器执行已编译的WebAssembly模块,这对于测试和自动化非常有用。 安装Node.js并在PATH中设置好,在执行go run或go test时,将-exec标志设置为go_js_wasm_exec所在的目录。默认情况下,go_js_wasm_exec位于Go安装的misc/wasm目录中。 GOOS=js GOARCH=wasm go run -exec="$(go env GOROOT)/misc/wasm/go_js_wasm_exec" . Hello, WebAssembly! GOOS=js GOARCH=wasm go test -exec="$(go env GOROOT)/misc/wasm/go_js_wasm_exec" PASS ok example.org/my/pkg 0.800s 在PATH中添加go_js_wasm_exec,可以在执行时不必每次都手动设置-exec标志,go run和go test能直接对js/wasm生效。 export PATH="$PATH:$(go env GOROOT)/misc/wasm" GOOS=js GOARCH=wasm go run . Hello, WebAssembly! GOOS=js GOARCH=wasm go test PASS ok example.org/my/pkg 0.800s 在浏览器中运行测试 也可以使用wasmbrowsertest在浏览器中运行测试。它可以自动完成网络服务器的工作,并使用无头的Chrome浏览器在其中运行测试,并将日志中继到控制台。 就像上一节那样,只需执行go get github.com/agnivade/wasmbrowsertest即可获取二进制文件。将其重命名为go_js_wasm_exec并将其放置到PATH中。 mv $GOPATH/bin/wasmbrowsertest $GOPATH/bin/go_js_wasm_exec export PATH="$PATH:$GOPATH/bin" GOOS=js GOARCH=wasm go test PASS ok example.org/my/pkg 0.800s 或者,使用-exec测试标志: GOOS=js GOARCH=wasm go test -exec="$GOPATH/bin/wasmbrowsertest" GoWebAssembly讲座 Building a Calculator with Go and WebAssembly 源码地址 Get Going with WebAssembly Go&WebAssembly简介 - by chai2010 与DOM交互 详细查阅syscall/js包。 其他项目: gas-WebAssembly应用程序的基于组件的框架 app-基于React兼容PWA的自定义工具框架 Vugu-wasm Web UI库,具有HTML布局,带有Go格式的应用程序逻辑,单个文件组件,快速开发和原型工作流程 vue -WebAssembly应用程序的渐进框架 dom-用于简化DOM操作的库 webapi-绑定生成器 vert-Go和JS值之间的WebAssembly互操作 GoWebian-用于纯粹地构建页面并添加WebAssembly绑定的库 Canvas go-canvas-Canvas绘图库,Simple demo 使用net/http时配置fetch options 可以使用net/http库从Go发出HTTP请求,这些请求将转换为fetch调用。 但是,fetch options 和 http 客户端选项之间没有直接映射。 为此,我们有一些特殊的标头值,这些标头值被认为是fetch options。如下表所示: 选项 描述 默认有效值 其他有效值 js.fetch.mode 设置Fetch API 模式 same-origin cors、no-cors、navigation js.fetch.credentials 设置Fetch API 证书 same-origin omit、include js.fetch.redirect 设置Fetch API重定向 follow error、manual 因此,如果想在发出请求时将模式设置为cors,则将类似于: req, err := http.NewRequest("GET", "http://localhost:8080", nil) req.Header.Add("js.fetch:mode", "cors") if err != nil { fmt.Println(err) return } resp, err := http.DefaultClient.Do(req) if err != nil { fmt.Println(err) return } defer resp.Body.Close() // handle the response 请随时订阅#26769,以获取更多信息和可能的更新。 编辑器配置 在Goland和Intellij Ultimate中设置WebAssembly的具体步骤,参考这里。 Chrome中的WebAssembly 如果运行较新版本的Chrome,则会有一个标志(chrome://flags#enable-webassembly-baseline)启用新编译器Liftoff,这将大大缩短加载时间,更多信息在这里。 调试 WebAssembly尚不支持调试器,因此,现在需要使用良好的 println()方法在JavaScript控制台上显示输出。 已经创建了一个官方的WebAssembly调试子组来解决此问题,并且正在进行一些初步调查和提议: WebAssembly Debugging Capabilities Living Standard源代码 DWARF for WebAssembly Target源代码 如果对调试器方面有兴趣,请参与并帮助实现这一目标。 分析WebAssembly文件的结构 WebAssembly代码资源管理器对于可视化WebAssembly文件的结构很有用。 单击左侧的十六进制值将突出显示其所属的部分,并在右侧显示相应的文本表示形式 单击右侧的一行将在左侧突出显示它的十六进制字节表示 已知错误 1.11.2之前的Go版本存在一个错误,该错误可能在某些(罕见)情况下生成错误的wasm代码。 如果您的Go代码可以毫无问题地编译为wasm,但是在浏览器中运行时会产生如下错误:CompileError: wasm validation error: at offset 1269295: type mismatch: expression has type i64 but expected f64,那么可能会遇到此错误。 解决方案是升级到Go 1.11.2或更高版本。 示例 更多示例点击这里。 减少Wasm文件的大小 目前,Go会生成大型的Wasm文件,可能的最小大小约为2MB。如果您的Go代码导入了库,则此文件的大小可能会急剧增加。 10MB +是常见的。 目前有两种主要方法来减小此文件的大小: 1. 手动压缩.wasm文件 使用gz压缩将示例WASM文件的2MB(最小文件大小)减小到大约500kB。使用Zopfli进行gzip压缩可能会更好,因为它提供的结果比gzip --best更好,但是运行时间要长得多。 使用Brotli进行压缩,文件大小明显优于Zopfli和gzip --best,并且压缩时间也在两者之间。这种(新的)Brotli压缩工具看起来很合理。 压缩对比 例子1 大小 命令 压缩时间 16M 未压缩大小 N/A 2.4M brotli -o test.wasm.br test.wasm 53.6s 3.3M go-zopfli test.wasm 3m 2.6s 3.4M gzip --best test.wasm 2.5s 3.4M gzip test.wasm 0.8s 例子2 大小 命令 压缩时间 2.3M 未压缩大小 N/A 496K brotli -o main.wasm.br main.wasm 5.7s 640K go-zopfli main.wasm 16.2s 660K gzip --best main.wasm 0.2s 668K gzip main.wasm 0.2s 使用 https://github.com/lpar/gzipped 之类的东西来自动提供带有正确标题的压缩文件(如果可用)。 2. 使用TinyGo生成Wasm文件 TinyGo支持面向嵌入式设备的Go语言的子集,并具有WebAssembly输出目标。 尽管确实有局限性(尚无完整的Go实现),但它仍然相当强大,并且生成的Wasm文件很小。 10kB并不罕见。 “ Hello world”示例为575字节。如果您将gz -6设为gz,它会下降到408个字节。 该项目也非常积极地开发,因此其功能正在迅速扩展。有关将WebAssembly与TinyGo结合使用的更多信息,请参见这里。 其他关于WebAssembly的资源 Awesome-Wasm-大量其他Wasm资源的清单。不是具体针对Go语言的。