go 打开二进制_Go 和 WebAssembly: 在浏览器中运行 Go 程序

Go语言中文网,致力于每日分享编码、开源等知识,欢迎关注我,会有意想不到的收获!

昨晚发布的一个微头条,引起了大家激烈的讨论:

1683fbaacd26f0eee167ac470cc90e5e.png

于是乎,趁热,咱们来一篇文章介绍 Go 和 wasm。


很长一段时间以来,Javascript 是在 Web 开发者中的通用语言。如果你想写出一个稳定、成熟的 Web 应用程序,那么使用 Javascript 几乎是唯一的方法。

WebAssembly(也叫 wasm )即将改变这种情况。使用 WebAssembly,现在可以用任何语言来编写 Web 应用程序。在这篇文章当中,我们将明白怎样编写 Go 程序并使用 wasm 在浏览器中运行它们。

1cdba1813d614f4bad482b442c8eab01.png

首先,什么是 WebAssembly

WebAssembly 官方网站 webassembly.org 对它的定义是“一个基于堆栈的二进制指令格式的虚拟机”。这是一个很好的定义,但是让我们来将它分解为我们能够简单理解的内容。

从本质上讲,wasm 是一种二进制格式,就像 ELF、Mach 和 PE 一样。唯一的区别是它适用于虚拟编译目标,而不是真正的物理机。为什么是虚拟机?因为与 C/C++ 的二进制不一样,wasm 二进制不针对于特定平台。因此,你可以不用改变任何东西而在 Linux、Windows 和 Mac 上使用同一份二进制文件。但是,我们需要额外的“代理”,它将 wasm 指令中的二进制文件转换为特定平台的指令并运行它们。通常,这个“代理”就是一个 Web 浏览器,但是理论上讲,它可以是任何其它东西。

这为我们提供了一个通用的编译目标,我们可以使用自己选择的任何编程语言来构建 Web 应用程序。只要我们将程序编译为 wasm 格式,我们就不用担心目标平台。就像我们编写一个 Web 应用程序,但现在我们可以使用我们选择的任何语言编写它。

Hello WASM

让我们尝试从编写一个简单的“ hello world ”程序开始。确保你的 Go 版本至少为 1.11。我们可以这样写:

8d634e41906cdf8bf4c75fe764253809.png

保存为一个 test.go 文件。这看上去就是一个常规的 Go 程序。现在让我们来编译这个文件到 wasm 平台。我们需要像下面这样设置 GOOS 和 GOARCH 来编译它。

$GOOS=js GOARCH=wasm Go build -o test.wasm test.go

我们现在就生成了 wasm 二进制文件。但是与本机系统不同,我们需要在浏览器中运行它。为此,我们需要投入一些额外的东西来实现这一个目标:

  • 一个将为我们 Web 应用程序提供服务的 Webserver
  • 一个 index.html 文件,包含一些用于加载 wasm 二进制文件的 JS 代码
  • 一个 JS 文件,用于作为浏览器和我们的 wasm 二进制文件之间的通信接口

我喜欢把它想象成制作飞天小女警所需要的东西。

a69d10c07b0b2a7deaa0e50f8e68a150.png

然后 BOOM,我们就有了一个 WebAssembly 应用程序!

我们已经在 Go 发行版本中提供了 HTML 和 JS 文件,在此我们将它们复制下来。

f2dc0d9c46e77d87711f74e7e53ff980.png

serve 是一个简单的 Go 二进制文件,它为当前目录中的所有文件提供服务。但是几乎所有的 Web 服务器都会这样做。

一旦我们运行它,并打开我们的浏览器。我们看到一个 Run 按钮,点击它,将执行我们的应用程序。然后我们点击它并检查控制台:

02987534c128e8a862e7bf3369921380.png

优美!我们刚刚使用 Go 编写了一个程序并在浏览器中运行了它。

到现在为止还挺好。但这是一个简单的“ hello world ”程序。一个现实世界中的 Web 应用程序需要与 DOM 进行交互。我们需要对按钮点击事件进行响应,从文本框中获取数据,并将数据发送回 DOM。现在我们将构建一个最小的图片编辑器,这个示例将用到所有的这些功能。

DOM API

首先,为了让 Go 代码与浏览器进行交互,我们需要一个 DOM API。我们需要 syscall/js 库来帮助我们解决这个问题。它是一个非常基础但却强大的 DOM API,我们在其上构建我们的应用程序。在我们转向制作我们的应用程序之前,让我们快速了解它的一些功能。

回调

为了响应 DOM 事件,我们声明了回调并用这样的事件将它们连接起来:

ab31384360a2a46a3316fb8c671f8db8.png

更新 DOM

要从 Go 内部更新 DOM,我们可以这样做 -

40528f6a39ea76ea1365527fa1848236.png

你甚至可以调用 JS 函数和操作本地原生 JS 对象,就像 FileReader 或 Canvas 一样。请随时查看 syscall/js 文档以获取更多详细的信息。

好了,现在开始构建我们的应用程序!

一个像样的 Web 应用

我们将构建一个小的应用程序,它将获取一个图片输入,然后对图片进行一个操作,如亮度、对比度、色调、饱和度,最后将图片输出回浏览器中。每一个效果都将会用滑块,用户可以更改这些效果并实时查看目标图像的变化。

首先,我们需要从浏览器获取输入图片到我们的 Go 代码中,以便我们可以处理它。为了有效的做到这一点,我们需要采取一些 unsafe 技巧,具体细节跳过。一旦我们获取到了图片,它就完全在我们的掌控之下了,我们就可以随心所欲的做任何事情。下面是图片加载器回调的简短片段,为简洁起见略有优化:

981fcae6f5c2a870bc4d0658bfcaccd6.png

然后我们从任何效果滑块中获取用户的值,并操纵图片。我们使用很棒的 bild 库。这是操作对比度回调的一小部分片段:

26729d20d714d654d19f1e81c4a5ae43.png

在此之后,我们将图片编码为 jpeg 格式并将其发送回浏览器。这是完整的应用程序操作:

我们加载图片:

9f423b6af63492cda59a627aaf6299ae.png

改变对比度:

0bc1de34691becfb4059e1a9d40ebcde.png

改变色调:

025fd8d6db4e988b1fc76b132909ebe1.png

太棒了,我们可以在浏览器中本地操作图片而不需要编写一行 Javascript 代码!可以在 https://github.com/agnivade/shimmer 找到源码。

请注意,所有这些都是在浏览器本身中完成的。这里没有 Flash 插件、JavaApplets 或 Silverlight。开箱即用的浏览器本身对 WebAssembly 提供了支持。

最后说两句

我的一些结束语:

  • 由于 Go 是一门垃圾回收的语言,因此整个运行周期都是在 wasm 二进制文件当中。正因为如此,这些二进制文件通常是 MB 级别的大小。与 C/Rust 语言相比,这是一个痛点;因为向浏览器发送 MB 级别的数据是不理想的。然而,要是 wasm 规范本身支持 GC,那么这可能会改变。
  • 在 Go 中对 wasm 进行支持官方在进行试验。syscall/js API 本身是在不断变化,将在可能还会变。如果你发现一个 bug,请在我们的 issue tracker 上提出 issue。
  • 与所有集数一样,WebAssembly 也不是一颗银弹。有时,简单的 JS 更快更容易编写。然而,wasm 本身正在开发中,并将推出更多的功能。线程支持就是这样一个特性。

希望这篇文章展示了 WebAssembly 一些很酷的方面,以及如何使用 Go 编写一个功能齐全的 Web 应用程序。如果你发现一个 bug,请尝试解决一下,并提出 issue。如果您需要任何帮助,请随时访问 #webassembly 频道。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值