开源中国

我们不支持 IE 10 及以下版本浏览器

It appears you’re using an unsupported browser

为了获得更好的浏览体验,我们强烈建议您使用较新版本的 Chrome、 Firefox、 Safari 等,或者升级到最新版本的IE浏览器。 如果您使用的是 IE 11 或以上版本,请关闭“兼容性视图”。
WebAssembly 和 Go:对未来的观望 - 技术翻译 - 开源中国社区

WebAssembly 和 Go:对未来的观望 【已翻译100%】

oschina 推荐于 4周前 (共 7 段, 翻译完成于 07-30) 评论 6
收藏  
22
推荐标签: Go WebAssembly 待读

我反对学习 JavaScript 还有前端开发已经不是秘密了。事实上,在 CSS 出现前我就学会了 HTML,不过 JavaScript 是我做 Web 开发好久后的事情了。当看到现代 Web 的发展时,我感到不寒而栗。这个生态对于脱离已久的我来说是如此迷茫。Node, webpack, yarn, npm, frameworks, UMD, AMD,我的天啊!

目前我关注 WebAssembly 也已经有段时间了,期望它能让我在没有典型 JavaScript 构建的情况下编写 Web 应用程序。

当听到 WebAssembly(wasm) 最近支持 Go 语言时,我知道实验的时机已经成熟,并且迫切期待尝试。在尝试之前我读了些好文章,而这篇文章将记录我的一些体验。

lnovonl
 翻译得不错哦!

为了用 Go 来写 wasm,你需要先下载 Go 源码并编译好。从 Go 1.11 开始,WebAssembly 将被原生支持,但现在还没有 release。

你可以按照这里的步骤来编译 Go。因为 Go 本身也是用 Go 语言实现的,所以在编译之前你需要先有一个可以正常工作的 Go 二进制版本来自举自己。最终,你系统里会有两个不同的 Go 版本。注意:如果你后面忘了你系统里安装了两个版本的 Go,那可能会给你造成一些困扰。可以使用 direnv 来管理 Go 版本,这样你就可以为不同的项目来配置不同的 Go 了。

安装最新的 Go 后,就可以体验 WebAssembly 了。你需要一个 HTML 文件和一个 JavaScript 脚本来加载生成的 wasm 文件。这些都包含在 Go 安装路径下的 misc/wasm 目录里。你可以复制它们到项目目录,修改它们以加载你的 wasm 文件。

xiaoaiwhc1
 翻译得不错哦!

我的第一个项目有点雄心勃勃,我打算用 Go 语言构建一个看起来像 Web 组件的东西,编译成 WebAssembly。我并没有把整件事做完,因为我被每件事要如何都做得好弄得心烦意乱。

首先,我将 GOROOT/misc/wasm 中的 HTML 和 JavaScript 文件复制到一个新目录中,并添加了一个 main.go 文件。根据我预先想好的计划,我把 HTML 放进 DOM 的一个现有节点,这个 DOM 要在 HTML 中声明。所以我创建了一个带有 thing 作为 ID 的 HTML section 标签。

<section class="main" id="thing" >Please wait...</section>

我在 HTML 文件底部的脚本标签上面插入了这个。接下来,我知道我想程序化地替换这个节点,所以我查找了 Go 的 wasm 库中与 DOM 交互的语法。为 Go 添加了一个 syscall/js 包,允许与 DOM 进行交互。我使用了这段 Go 代码得到了一个 HTML 带有 thing 作为 ID 的节点的引用:

el := js.Global.Get("document").Call("getElementById", "thing")
kevinlinkai
 翻译得不错哦!

现在我有一个空DOM节点的引用,我可以使用渲染的HTML来填充。因此下一步其实就是创建一些HTML并将其填充进去。

我将著名的TodoMVC应用作为灵感。首先我创建两个文件:todo.go和todolist.go。这些文件包含一些Go结构来表示Todo事项,和Todo事项列表。

type Todo struct {
	Title     string
	Completed bool
	//Root      js.Value
	tree *vdom.Tree
}

type TodoList struct {
	Todos []Todo
	Component
}

type Component struct {
	Name     string
	Root     js.Value
	Tree     *vdom.Tree
	Template string
}

我也有点自大,开始将东西提取到Component类型中,并认为我可以将它嵌入到我的自定义类型中,以便向它们提供Web 组件功能。我没有完成这个想法。。。在后文你会看到原因。

这些自定义Go类型每一个都有一个Render()方法和模板:

var todolisttemplate = `<ul>
{{range $i, $x := $.Todos}} 
	{{$x.Render}} 
{{end}}
</ul>`
func (todoList *TodoList) Render() error {

	tmpl, err := template.New("todolist").Parse(todoList.Template)
	if err != nil {
		return err
	}
	// Execute the template with the given todo and write to a buffer
	buf := bytes.NewBuffer([]byte{})
	if err := tmpl.Execute(buf, todoList); err != nil {
		return err
	}
	// Parse the resulting html into a virtual tree
	newTree, err := vdom.Parse(buf.Bytes())
	if err != nil {
		return err
	}

	if todoList.Tree != nil {
		// Calculate the diff between this render and the last render
		//	patches, err := vdom.Diff(todo.tree, newTree)
}		//	if err != nil {
		//		return err
		//	}

		// Effeciently apply changes to the actual DOM
		//		if err := patches.Patch(todo.Root); err != nil {
		//			return err
		//		}
	} else {

		todoList.Tree = newTree
	}
	// Remember the virtual DOM state for the next render to diff against
	todoList.Tree = newTree

	todoList.Root.Set("innerHTML", string(newTree.HTML()))
	return nil
}


我的想法是用我找到的vdom包来做这些渲染,这样的话渲染的效率会更高一些。这就是我遇到的第一个问题。

琪花亿草
 翻译得不错哦!

GopherJS和Go/wasm之间的区别

vdom包专为GopherJS而写,而GopherJS是一个从Go到Javascript的转译器。基于便捷,GopherJS使用js.Object类型。Go的新wasm库syscall/js使用js.Value类型。它们精神上是相似的,但在实现上大为不同。这意味着我使用vdom渲染的想法是行不通的,除非我将vdom使用的js.Object移植到使用js.Value。尽管vdom的tree.HTML()函数在不用修改的情况下就可以运行,因此我可以将HTML节点的内部HTML设置为vdom解析出的内容。Render()函数解析Go结构模板,将Go结构的实例作为上下文来传值。然后它用vdom库创建一个解析dom树,而且在函数的最后一行渲染树:

todoList.Root.Set("innerHTML", string(newTree.HTML()))

此时,我已经有了一个可以运行的Go/wasm原型,没有连接任何事件。但是它确实可以渲染成dom并显示在浏览器。这是巨大的一步;我当时很兴奋。

我创建了一个Makefile,这样我就不用一次又一次的输入冗长的编译命令:

wasm2:
	GOROOT=~/gowasm GOARCH=wasm GOOS=js ~/gowasm/bin/go build -o example.wasm markdown.go

wasm:
	GOROOT=~/gowasm GOARCH=wasm GOOS=js ~/gowasm/bin/go build -o example.wasm .

build-server:
	go build -o server-app server/server.go

run: build-server wasm
	./server-app


基于现在的Web Assembly状态,这个makefile也指出了一个至关重要的问题。新型浏览器会忽略WASM文件,除非给他们提供合适的MIME类型。这篇文章有一个简单的HTTP文件服务器,它为web assembly文件设置了正确的MIME类型。我将其复制到我的项目,并将其用于应用中。如果你的web服务器确实为.sasm文件配置好了,那么你就不需要自定义服务器。

琪花亿草
 翻译得不错哦!

提出挑战

在这一点上,我意识到Web Assembly可以正常运行,而也许更重要的是:GopherJS的很多代码很少甚至不用修改就可以在Web Assembly可以正常运行。我给自己提出挑战( nerd sniped)。我尝试的下一件事情是找一个vecty应用并编译它。由于vecty是专为GopherJS所写,而且使用了js.Object类型而不是js.Vaule,因此要想失败很困难。为了让vecty在wasm中编译,我fork了vecty,然后做了一些修改,一些处理,并注释了很多代码。

最终的结果就是放在在vecty/example目录中的markdown编辑器可以在Web Assembly中完美运行。本文有点冗长,因此我会让你在这看源码。总结:它与GopherJS版本几乎完全相同,但是在main()退出的时候web assembly也会退出,因此为了阻止退出并保持应用运行,我在main()结尾添加了一个空的通道接收。

琪花亿草
 翻译得不错哦!

事件

Go 的 syscall/js 使用了一个非常不同的方法来进行事件注册,我不得不修改 vecty 的事件注册代码才能使用 wasm 新的回调注册,在这里我花了非常多的时间。不过直到现在,这个方法工作的还不错。

结论

通过对这些事件课程的学习,我认定 WebAssembly 就是 Web 开发的未来。它可以使用任何语言作为“前端语言”来进行 Web 开发,然后编译为 wasm 就可以了。这给像我一样并不想再学习 Javascript,而可以使用自己喜欢的语言来进行 Web 开发的人带来了很多好处。

你可以从这里下载源代码,不过记住:风险自担。

xiaoaiwhc1
 翻译得不错哦!
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们
评论(6)
Ctrl/CMD+Enter

dart呢
wasm支持操作DOM,等技术成熟,各大浏览器都支持wasm,必然会产生基于wasm的前端框架,到时js真的可能被替代了

引用来自“橙汁儿”的评论

dart呢
不成功便成仁,现在还有人用吗?
太偏执了
倒时候倒是看好C#、java之类语言
如果各种语言都能用来开发 WebAssembly ,能不能终结 js 在 web 上的统治地位?
顶部