当我第一次听见 WebAssembly 消息的时候就觉得它非常酷,我迫不及待地想要开始尝试使用它。然而当我不久之后开始使用 WebAssembly 的时候 ,它给我我最大的感受却是令人泄气。这篇文章的目的就是让你避免这些令人沮丧的部分。
读者须知
这篇文章写于 2016 年六月 24 号, WebAssembly 还是一个非常新并且不稳定的技术,随着 WebAssembly 在各个浏览器中形成规范,这篇文章里的说的所有东西都有可能变成错误的。
有了这些说明……
到底什么是 WebAssembly ?
嗯,官方网站的说明就是这样的
WebAssembly or wasm is a new portable, size- and load-time-efficient format suitable for compilation to the web.
蛤?什么?什么的格式?文本?二进制?老实讲这就是个垃圾说明。
所以,拿出你的小笔记本儿,我会用上我关于 wasm 的一切经验来给出我自己对 Wasm 的说明
WebAssembly 或者 wasm 是一个用于撰写高性能,浏览器无关的网页组件的字节码规范
所以我们还不能一句话说清楚它到底哪里好,不过这里就是说明的余下的部分。
WebAssmbly 通过使用比运行时动态类型变量更高效的静态类型变量引用,实现了性能上的提升。它是由 W3C Community Group 开发,最终能被遵循规范的浏览器兼容。而 WebAssembly 的杀手级特性就是,你最终将可以用任意的语言都来编写这些网页组件
现在听起来是不是厉害多了?
让我们开始吧
每当要开始学习一项新的事物,我通常会寻找一个最小的可行范例来研究它是如何工作的。不幸的是,对我们来说还没有实际的 WebAssembly 的例子。就目前状况来看, wasm 基本上只是一个字节码规范而已。假设我们回到 1996年,一些来自 Sun 软件公司的工程师在介绍 JVM……不是 Java 。我想象中那个会议可能有点像这样
“嘿,大伙儿来看看我们造的这个字节码虚拟机”
“雕,那我们该如何写代码使用它?”
HelloWorld in bytecode
“嗯……厉害..,我会找个时间来看看它的”
“吼啊,请务必让我们知道你的想法,要是你用的时候出了什么差错,记得到我们的 github 主页上给我们留个言”
“你说得太对了,我们还是去看看 github 里的其他项目吧”
即使这个例子因为 JVM 是基于 java 的,所以是一个坏的例子,但我希望你能明白个中重点
如果你的字节码不能在那个场景里被编译它的工具展示出来,你就会有一个非常尴尬的时刻了。所以说,我们到底要如何开始它呢?
在 WebAssembly 之前我们需要知道
大多数技术都是某种革新的结果,尤其是一个合理的尝试会使之逐渐成为一个正式的规范。 Wasm 也没有什么不同,因为它实际上是对 asm.js 所做工作的一种延续。其中 asm.js 是通过静态类型,使之可以被编译的一种javascript 组件编写方法规范。而 Wasm 延续了这个想法,通过制定一个字节码规范使得 Wasm 可以从任何语言编译而来。随着时间的推移,有许多主流浏览器选择传输二进制文件来代替编码过的文本,而不仅仅是 Mozilla 这样做。
asm.js 只是一个使用 javascript 最小语言特性子集的 javascript 的编写规范。你完全可以手写一个简单的 asm.js 例子,如果你愿意弄脏你的手,这就是一个开始学习的好方法(最好在稍后把这些放到一个单独的文件中,并按照惯例使用 your-module-name.asm.js
命名)
|
|
这不是一个非常有用的函数,不过它是符合规范的。如果你觉得这看起来有点傻,你不是一个人,不过几乎这里每一个字符都是必须的。所有这些一元操作符号 ‘+’ 是作为类型说明而存在,让编译器知道那些带有’+’符号的变量是双精度类型,而无需在运行时才去推断出他们是什么类型。他的语法非常严苛,不过假如你弄错了写什么,火狐中的控制台会给你一个错误原因来告诉你哪里运行出错了。
如果你想在浏览器中运行它,可以像这样去运行它
|
|
如果你没做错任何事,那输出应该看是像这样的
这就是 WebAssembly 了
现在我们有一个可用的 asm.js 的部件了,我们可以使用由 WebAssembly github page 提供的工具将他编译成 wasm。现在你需要自己去去克隆这个仓库并构建这个工具。这是最糟糕的一部分。因为这些工具仍在不断地开发中,因此不时出现断层式改动都是司空见惯的事情。尤其是当你在 window 环境下的时候。
无论你是在 windows 还是 mac ,你都会需要 make 和 cmake 这两个命令行工具安装在你的系统中。如果你在 windows ,你还需要安装上 visual studio 2015 。如果你在 mac 环境中,请查看这些说明,同样的如果你是在 windows 环境中查看这些说明
在 windows 中构建二进制文件
直接分发该工具的可用二进制文件会是 WebAssmbly 团队迈向正确方向的重要一步。
如果你设法让编译成功,你会看见这个目录下有一个 bin 文件夹被创建,里面包含了一些我们可以用来编译我们的 asm.js 文件为 wasm 的工具。
第一个工具是 asm2wasm.exe
。这个工具将 asm.js 代码编译成 .s
的格式化代码,这个.s
里面是抽象语法树(AST)的文本表述,用于 wasm 的。一旦你运行这个工具,最终结果会是这样:
|
|
以后有机会我们可以逐句逐句解析它,但就现在而言,我只是想要向你展示它是什么样的。既然说到 wasm 是一个字节码格式,想要像你对其他 javascript 代码做的那样,直接右键点击并查看代码是不行的。他看上去会更像上面的字节代码。目前的计划是只有当你在 wasm 组件里查看源码时,wasm 才会解析这个字节码,让它变得可被人类阅读的。
我们下一件需要做的事是进一步编译这个 .s
格式的代码为 wasm 二进制代码,我们会用到 wasm-as.exe
将其汇编化。运行了这个文件之后,你最终会的到一份实际上需要用到浏览器的 wasm 字节码。
将 asm.js 编译成 wasm 字节码
然后,拿出你手上的 firefox 或者 chrome canary 的最新副本,启用 WebAssmbly 特性
在火狐里。你要去输入about:config
到地址栏中,然后告诉它你会小心的。在这之后,输入 wasm 到搜索栏中并双击 javascript.potions.wasm
直到它的值变成 true
然后重启火狐浏览器
对于 Chrome Canary 来说,你需要输入 chrome://flags
到地址栏中并向下滚动直到你找的 Experimental WebAssembly
,点击启用链接并重启浏览器。
最后一步就是将这个 wasm 模块跑在浏览器中。 这是另一个痛苦的地方,因为当我第一次尝试的时候这完全是隐藏起来的,我从规范中找不到任何关于调用 wasm 模块的 javascript API 说明。最终,我只好打开 Chrome Canary 的控制台然后敲入 WebAsse
结果并没有任何相关信息弹出来。接下来我尝试敲入Was
,结果居然有了!。看起来这个对象仍处于最缺失文档的初始阶段。这件事发生在我用另一个工具(emscripten)去编译 Wasm 的时候,关于我具体做了什么的那是另一篇博客的主题了。不管怎么说,在我做了那些事了以后,我能够做出一个可用的例子了。
在我到处点击,并最终决定设计一个并 repo 给 WebAssembly 的时候 ,我看见一个名叫 Js.md 的文件,于是我点开了它,不用说,那里他娘的当然有一个现成的带着文档的 javascript Api 。最引人注意的斜体文字在这个文档的顶部。结果的是这文档最好的部分是在非常底部的一小部分,它非常简单的向你展示了如何加载一个模块。我唯一需要做的就是将其中相应的部分替换掉并尝试用它
|
|
把这些折腾进一个 html 文件中,在你的本地文件夹中搭建一个服务器,然后加载它。
这救是我在两个浏览器所能看到的结果:
wasm 跑在浏览器中(至少尝试过了)
我猜是时候去写一个 bug 报告了。记住,这完全是个实验性的技术并且非常不稳定,所以当发生像这样事情的时候,千万不要过分沮丧。
恭喜你!
你已经创建了你的第一个 WEbAssembly 组件了,下一步是什么?我们只是简单的在表面掠过而已。手写 asm.js 就是这个例子中挺重要的部分,但是要做有任何非凡的事情都需要很长的时间和非常多的耐心。使用 emscripten 来编译一个非凡的 asm.js 小应用相比之下要简单太多了。在那个 javascript Api 文档中。我十分建议你阅读有关 asm.js 的规范,尤其是关于内存模块描述,因为其中有许多概念都转移到 WebAssembly 当中了。
另一个笑话就是现在你还不能直接传递一个数组当作函数的参数。这里中的一些协议明显应当被修改的,但是在这个规范中还没有明显的改动。去加上你的看法吧
其他需要注意的是,当你开始用 Wasm 做些不平凡的事情的时候,你可能会发现在 WebAssemly 中的实际效果比原生 js 代码还慢。只需记得的是现代 javascript 引擎在编译 javascript 的过程中经过了高度的优化的而这些差距是需要给 wasm 汇编一些时间迎头赶上。WebAssembly 真的还没准备好用于生产环境。
如果你有什么问题关于 wasm 或者是这里提到的一些工具,请到 Stack Overflow 提问并加上适当的标签。