博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【译】Go和WebAssembly:在浏览器中运行Go程序
阅读量:6913 次
发布时间:2019-06-27

本文共 4114 字,大约阅读时间需要 13 分钟。

在过去很长一段时间里,Javascript是Web开发人员中的通用语言。如果你想写一个稳定成熟的 Web 应用程序,用javascript几乎是唯一的方法。

WebAssembly(也称为wasm)将很快改变这种情况。使用WebAssembly可以用任何语言编写Web应用程序。在本文中,我们将了解如何编写Go程序并使用wasm在浏览器中运行它们。

但首先,什么是WebAssembly

将其定义为“基于堆栈的虚拟机的二进制指令格式”。这是一个很好的定义,但让我们将其分解为我们可以轻松理解的内容。

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

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

你好 WASM

让我们从一个简单的“hello world”程序开始,但是要确保您的Go版本至少为1.11。我们可以这样写:

package mainimport (    "fmt")func main() {    fmt.Println("hello wasm")}

保存为test.go。看起来像是一个普通的Go程序。现在让我们将它编译为wasm平台程序。我们需要设置GOOSGOARCH

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

现在我们生成了 wasm 二进制文件。但与原生系统不同,我们需要在浏览器中运行它。为此,还需要再做一点工作来实现这一目标:

  • Web服务器来运行应用
  • 一个index.html文件,其中包含加载wasm二进制文件所需的一些js代码。
  • 还有一个js文件,它作为浏览器和我们的wasm二进制文件之间的通信接口。

我喜欢把它想象成制作The PowerPuff Girls所需要的东西。

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

现在Go目录中已经包含了html和js文件,因此我们将其复制过来。

$cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .$cp "$(go env GOROOT)/misc/wasm/wasm_exec.html" .$# we rename the html file to index.html for convenience.$mv wasm_exec.html index.html$ls -ltotal 8960-rw-r--r-- 1 agniva agniva    1258 Dec  6 12:16 index.html-rwxrwxr-x 1 agniva agniva 6721905 Sep 24 12:28 serve-rw-rw-r-- 1 agniva agniva      76 Dec  6 12:08 test.go-rwxrwxr-x 1 agniva agniva 2425246 Dec  6 12:09 test.wasm-rw-r--r-- 1 agniva agniva   11905 Dec  6 12:16 wasm_exec.js

serve是Go二进制文件,是一个Web服务器。但几乎任何Web服务器都可以。(译者注:原文并没有提供serve二进制文件的源代码,相信聪明的你一定知道怎样编写。)

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

真牛,我们刚刚在Go中编写了一个程序并在浏览器中运行它。

到现在为止一切顺利。但这是一个简单的“hello world”程序。真实的Web应用程序需要与DOM交互。我们需要响应按钮单击事件,从文本框中获取输入数据,并将数据发送回DOM。现在我们将构建一个最小的图像编辑器,它将使用所有这些功能。

DOM API

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

回调

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

import "syscall/js"// Declare callbackcb := js.NewEventCallback(js.PreventDefault, func(ev js.Value) {    // handle event})// Hook it up with a DOM eventjs.Global().Get("document").    Call("getElementById", "myBtn").    Call("addEventListener", "click", cb)// Call cb.Release() on your way out.

更新DOM

要从Go中更新DOM,我们可以

import "syscall/js"js.Global().Get("document").        Call("getElementById", "myTextBox").        Set("value", "hello wasm")

您甚至可以调用JS函数并操作本机JS对象,如 FileReaderCanvas。查看文档以获取更多详细信息。

正确的 Web 应用程序

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

首先,我们需要从浏览器获取输入的图像给到我们的Go代码,以便可以处理它。为了有效地做到这一点,我们需要采取一些不安全的技巧,这里跳过具体细节。拥有图像后,它完全在我们的控制之下,我们可以自由地做任何事情。下面是图像加载器回调的简短片段,为简洁起见略有简化:

onImgLoadCb = js.NewCallback(func(args []js.Value) {    reader := bytes.NewReader(inBuf) // inBuf is a []uint8 slice where our image is loaded    sourceImg, _, err := image.Decode(reader)    if err != nil {        // handle error    }    // Now the sourceImg is an image.Image with which we are free to do anything!})js.Global().Set("loadImage", onImgLoadCb)

然后我们从效果滑块中获取用户值,并操纵图像。我们使用了很棒的库。下面是回调的一小部分:

import "github.com/anthonynsimon/bild/adjust"contrastCb = js.NewEventCallback(js.PreventDefault, func(ev js.Value) {    delta := ev.Get("target").Get("valueAsNumber").Float()    res := adjust.Contrast(sourceImg, delta)})js.Global().Get("document").        Call("getElementById", "contrast").        Call("addEventListener", "change", contrastCb)

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

加载图片:

图片描述

改变对比:

改变色调:

太棒了,我们可以在浏览器中本地操作图像而无需编写一行Javascript! 源代码可以在找到。

请注意,所有这些都是在浏览器本身中完成的。这里没有Flash插件,Java Applet或Silverlight。而是使用浏览器本身支持的开箱即用的WebAssembly。

最后的话

我的一些结束语:

  • 由于Go是一种垃圾收集语言,因此整个运行时都在wasm二进制文件中。因此,二进制文件通常有几MB的大小。与C/Rust等其他语言相比,这仍然是一个痛点; 因为向浏览器发送MB级数据并不理想。但是,如果wasm规范本身支持GC,那么这可能会改变。
  • Go中的Wasm支持正式进行试验。syscall/js API本身也在不断变化,未来可能会发生变化。如果您发现错误,请随时在我们报告问题。
  • 与所有技术一样,WebAssembly也不是一颗银弹。有时,简单的JS更快更容易编写。然而,wasm规范本身正在开发中,并且即将推出更多功能。线程支持就是这样一个特性。

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

原文链接

转载地址:http://nlicl.baihongyu.com/

你可能感兴趣的文章
Python--day25--面向对象之多态
查看>>
数据结构-----树状数组
查看>>
新手学习python(十六)封装redis
查看>>
vuex
查看>>
vux 全局使用 loading / toast / alert
查看>>
org.tinygroup.validate-验证框架
查看>>
session共享方法
查看>>
ASP.NET AJAX web chat application
查看>>
Codeforces Round #566 (Div. 2) B. Plus from Picture
查看>>
自己动手制作一个本地的yum仓库
查看>>
Ubuntu下用命令行快速打开各类型文件(转)
查看>>
Magento多语言设置——优化前台与后台实现方法
查看>>
leetcode121买股票
查看>>
SQL SERVER 2008中启用相应的功能
查看>>
Implementing a small Cron service in C# - CodeProject
查看>>
REST::Neo4p – PERL版本的”OGM”
查看>>
linux中service *** start与直接运行/usr/bin/***的区别
查看>>
剑指offer题目java实现
查看>>
Linux内核之于红黑树and AVL树
查看>>
LoaderManager使用详解(二)---了解LoaderManager
查看>>