什么是webassembly

webassembly - 图1

WebAssembly是一种新的编码方式,可以在现代的网络浏览器中运行(Chrome, Edge, Firefox, 和使用WebKit的浏览器), 它是一种低级的类汇编语言,具有紧凑的二进制格式,可以接近原生的性能运行,并为诸如C/C ++等语言提供一个编译目标,以便它们可以在Web上运行。它也被设计为可以与JavaScript共存,允许两者一起工作。

webassembly的优点

  • 最大的优势就是性能,直接在浏览器运行编译完成的低级别的机器码会比jit的JavaScript有天然的优势。 WASM二进制代码的执行时间仅仅只比原生代码慢20%。
  • 可移植,编译完成的机器码,可以在不同平台运行,因为运行环境就是浏览器。
  • 多语言支持,可以让其他语言编写,然后运行在浏览器。目前c/c++,rust,golang,Swift,typescript,等等…(参见:https://github.com/appcypher/awesome-wasm-langs#assemblyscript)

浏览器的支持度

webassembly - 图2

详见:https://caniuse.com/#feat=wasm

webassembly如何运行

webassembly - 图3

可以使用其他语言,然后通过编译工具编译出机器码,然后在浏览器里面加载并运行。

目前对于 WebAssembly 支持情况最好的编译器工具链是 LLVM,还有一个易用的工具叫做 Emscripten,它通过自己的后端先把代码转换成自己的中间代码(asm.js),然后再转化成 WebAssembly,实际上它是基于 LLVM 的一系列编译工具的集合。
webassembly - 图4

简单的hello world

官方提供了一个工具链,可以直接把c语言编译成wasm在浏览器运行,以类Linux环境为例:

下载安装工具

  1. $ git clone https://github.com/juj/emsdk.git
  2. $ cd emsdk
  3. $ ./emsdk install latest
  4. $ ./emsdk activate latest

编写一个hello world的C代码

hello.c

  1. #include <stdio.h>
  2. int main(int argc, char ** argv) {
  3. printf("Hello, world!\n");
  4. }

编译代码并运行

  1. $ emcc hello.c -s WASM=1 -o hello.html
  2. $ emrun --no_browser --port 8080 .

工具会启动一个web server,会展示一个页面,在console显示hello world.

webassembly - 图5

JS是怎么调用wasm

  • 获取 .wasm 二进制文件,将它转换成类型数组或者 ArrayBuffer
  • 将二进制数据编译成一个 WebAssembly.Module
  • 使用 imports 实例化这个 WebAssembly.Module,获取 exports。

可以编写一个文本格式的wasm的s表达式(一种通用的方便跟踪和调试的wasm文本,详细介绍:https://en.wikipedia.org/wiki/S-expression ),可以通过:WABT(https://github.com/WebAssembly/wabt) 转成成二进制的wasm文件

simple.masm

  1. ;; simple.wasm
  2. (module
  3. (func $i (import "imports" "i") (param i32))
  4. (func (export "e")
  5. i32.const 42
  6. call $i))

转化命令(需要安装wabt工具):wat2wasm simple.masm

编写HTML:hello.html

  1. <!DOCTYPE html>
  2. <html lang="en-us">
  3. <head>
  4. <meta charset="utf-8" />
  5. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  6. <title>wasm</title>
  7. </head>
  8. <body>
  9. <script>
  10. var importObject = { imports: { i: arg => console.log(arg) } };
  11. function instantiate(bytes, imports) {
  12. return WebAssembly.compile(bytes).then(
  13. m => new WebAssembly.Instance(m, imports)
  14. );
  15. }
  16. fetch("simple.wasm")
  17. .then(response => response.arrayBuffer())
  18. .then(bytes => instantiate(bytes, importObject))
  19. .then(instance => instance.exports.e());
  20. </script>
  21. </body>
  22. </html>

更多的例子: https://github.com/mdn/webassembly-examples

要理解wasm主要还是要理解,执行过程,以及js的API,还有就是s表达式,对js暴露的方式,调用js的方式。

此外,如果要了解c/c++如何编译成wasm,需要看http://kripken.github.io/emscripten-site/index.html 或者 https://github.com/WebAssembly/binaryen