引子
Any application that can be written in JavaScript, will eventually be written in JavaScript. ——Atwood's Law
有人用 JavaScript 做语法词法解析,有人写了 x86 模拟器, 还有人用 JavaScript 写了可自举的 JavaScript 引擎。JavaScript 早已经在”重新发明一切”的路上一骑绝尘了,JavaScript 的流行也使它始终位于各大语言排行榜上的前列,这无疑是属于 JavaScript 程序yuan们最好的时代。
这并非是因为 JavaScript 是门优秀的语言 (恰恰相反),而是因为当今的世界是 Web 的世界,Web 的载体浏览器只会说 JavaScript。这难免使人眼红,王侯将相,世人无数次想要取代 JavaScript 的地位,目前为止的历史我们都看到了,无一不铩羽而归。求上不得,得其中,最新成果是大家(伙儿)齐心协力把 JavaScript 变成了新一代的汇编语言。请移步这里看大家的最新成果。
WebAssembly
去年 11 月 13 日,Mozilla 在其官方博客上发表了一篇文章,WebAssembly support now shipping in all major browsers,指出当今世界四大主流浏览器 Firefox,Chrome,Safari,Edge(排名分先后),都已经支持了名为 WebAssembly 的新技术,并回顾了一路走来的艰难历程。最后指出这是新时代的开端,大家一起欢呼吧。那么,WebAssembly 到底是啥?让我们发出发聋振聩的三连问:
可以吃吗?
请移步 WebAssembly 官网。官网解释如下:
WebAssembly or wasm is a new portable, size- and load-time-efficient format suitable for compilation to the web.
关键词:
- 可移植: WebAssembly 是一种可移植的二进制格式,它不依赖于具体的浏览器平台。
- 高效:WebAssembly 被设计为针对 Size 和 Load Time 进行优化的格式,可以在各个硬件平台上以 native speed 运行。
- 安全:WebAssembly 是运行在沙盒内的,甚至可以和当前的 JavaScript 虚拟机共享一套环境,并且也遵守浏览器各种跨域不跨域的规章制度。
- 开放:WebAssembly 是开放标准,不受某一家厂商控制(Oracle你听到了吗)。并且被设计为可以和 JavaScript API 和 Context 交互。
简而言之,WebAssembly 可以被看做是通过浏览器运行的某种高效的开放的二进制格式,并且可以和 JavaScript 环境互通。
WebAssembly 的目的是取代 JavaScript 吗?FAQ 这样回答:不,WebAssembly 是被设计来补充而不是替代 JavaScript。随着时间推移,越来越多的语言可以被编译为 WebAssembly,但是 JavaScript 还是作为 Web 唯一的动态语言而存在。
这样看来老二的位置摆得很正嘛。对于 WebAssembly, 笔者最看重的一点是作为开放标准的同时有粗大腿的支持 (M$ Google Apple Mozilla),这才是它有可能活下来的原因。问题是可以吃吗,答案当然是可以吃(佛系码农也可以不吃)。
怎么吃?
WebAssembly 同时存在一个二进制格式和一个文本的描述格式,这很像是机器语言和汇编语言的关系。这里我们用一个例子解释一下。
事实上,WebAssembly 可以被看作是运行在一个 structured stack virtual machine 里,懂行的朋友一眼就可以看出这和 Java bytecode 非常的像。所以大家不要以为 WebAssembly 是在重新发明 Flash 了,这货明明是在重新发明 Java Applet 啊,好吧 Silverlight 也有点像...。顺带一提,Android 的 Dalvik 为了效率,使用的是 register-based virtual machine。对 WebAssembly spec 感兴趣的朋友可以移步这里。
作为 WebAssembly 的 MVP,C/C++ 及其类库的支持是首当其冲的。因为基于 LLVM 的平台,所以理论 LLVM 支持的语言都可以编译为 WebAssembly,C/C++,rust,甚至 .net 和 Java 也可以编译到 WebAssembly,只不过托管语言都需要附带一个巨大的runtime。
下面我们以 C/C++ 为例,我们写一个函数给 JavaScript 使用。
步骤:
安装 WebAssembly 构建工具链 emscripten,针对 macOS,请参考这里
安装后,执行
emcc --version
判断是否成功-
创建 C++ source:
cat random.cc
include <random>
include <cmath>
extern "C" {
long normal_rand() {
static std::random_device rd{};
static std::mt19937 gen{rd()};return std::lround(std::normal_distribution<>(0, 100)(gen));
}
}
`</pre>这里用 C++ 产生一个正态分布,期望为
0
,方差100
的随机数,然后导出为一个 C 函数normal_rand
执行
emcc --bind -std=c++14 --emrun -s WASM=1 -s EXPORTED_FUNCTIONS='["_normal_rand"]' -O3 -o random.html random.cc
顺利的话会在当前目录生成如下文件
<pre>`$ ls -l
total 496
-rw-r--r-- 1 haoli staff 810 Dec 24 21:44 random.cc
-rw-r--r-- 1 haoli staff 102728 Dec 24 22:17 random.html
-rw-r--r-- 1 haoli staff 120624 Dec 24 22:17 random.js
-rw-r--r-- 1 haoli staff 20130 Dec 24 22:17 random.wasm
random.wasm
就是我们的 WebAssembly,random.js
和 random.html
是模板代码,帮助我们加载 WebAssembly。
执行 emrun --no_browser --port 8821 random.html
启动一个 WebServer
用支持 WebAssembly 的浏览器访问http://localhost:8821/random.html,然后在 console 里面执行 Module._normal_rand()
即可看到结果
怎么做好吃?
古往今来,在浏览器里面尝试改善 JavaScript 性能和增强功能的尝试大约都失败了吧,前有 ActiveX,Java Applet,Flash,后有 Silverlight,Flex,NaCl。WebAssembly 应该是各个浏览器大佬的最新尝试。不过这次大家都学乖了,没人指(xi)望一个私有标准会成功,于是联合起来开发一个开放的标准。
至少目前看来,结果还是很让人欣喜的。因为开放标准的缘故,除了上面的 emscripten,还有大量的工具开始支持 WebAssembly,甚至 clang 可以直接指定 target 为 WebAssembly。加上浏览器把诸如 DOM API 以及 WebGL API 都暴露给了 WebAssembly,应用场景相当可观。首当其冲的就是游戏厂商,Epic 和 Unity 都是 WebAssembly 的早期尝试者,他们已经把自己的游戏引擎移植到 Web 平台而不用重写代码。不仅如此, WebAssembly 还支持 non-web 的场景,比如 NodeJs 也开始支持 WebAssembly。WebAssembly 官网有个 use case 清单,列举了可能的应用场景。图形图像的处理,计算机辅助设计,AR/VR,VPN,加解密等等。到那时,前端可以玩出的花样,想象空间实在太大。
有点过于美好了哈,我们还是就此打住,拭目以待吧。
Reference
这里列举一些 WebAssembly 相关的资源,各位随喜:
- Funky Karts, 移植到 WebAssembly 的网页游戏,作者在网站记录了学习 WebAssembly 到移植成功的全过程。
- WasmExplorer,在线的 C/C++ to WebAssembly 编辑器,同时也可以查看 Assembly 内容。
- WasmFiddle,另一个在线编辑 WebAssembly 的工具
- WasmRocks WebAssembly 新闻站。
- emscripten 官网。
文/ThoughtWorks李好