WebAssembly初探

334 阅读3分钟

简介

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

WebAssembly 是一门不同于 JavaScript 的语言,但是,它不是用来取代 JavaScript 的。相反,它被设计为和 JavaScript 一起协同工作,从而使得网络开发者能够利用两种语言的优势:

  • JavaScript 是一门高级语言。对于写网络应用程序而言,它足够灵活且富有表达力。它有许多优势——它是动态类型的,不需要编译环节以及一个巨大的能够提供强大框架、库和其他工具的生态系统。
  • WebAssembly 是一门低级的类汇编语言。它有一种紧凑的二进制格式,使其能够以接近原生性能的速度运行,并且为诸如 C++和 Rust 等拥有低级的内存模型语言提供了一个编译目标以便它们能够在网络上运行。

浏览器兼容性

截至2022.07.04 WebAssembly兼容性,可见当前大部分主流浏览器均已支持。

image-20220704093650291.png

应用嵌入 WebAssembly

如下图所示,无论是 Web 应用还是非 Web 应用,都需要在宿主程序中嵌入 WebAssembly 运行时才能使用 WebAssembly。唯一的区别是,在Web应用程序中,宿主程序是浏览器,而在非Web场景中,宿主程序是自己的应用程序。

21321321321.png

简单示例

emscripten-diagram.png

通过 EMscripten 工具,可将新写的 C/C++ 代码编译为 WebAssembly 使用。

编译

首先,下载和安装 EMscripten参考官方文档:Emscripten下载和安装,安装完成后,就可以使用 Emscripten 相关的命令了

创建一个目录,新建一个 C++ 代码文件:

#include <emscripten.h>
extern "C" {
  EMSCRIPTEN_KEEPALIVE 
  int fibonacci(int n) {
    if(n < 2) {
      return 1;
    }
    return fibonacci(n - 1) + fibonacci(n - 2);
  }
}

函数的定义置在 extern "C" {} 结构中,是为了防止函数名编译后被改变。EMSCRIPTEN_KEEPALIVE 是为了确保函数不会在编译器的编译过程中,被 DCE(Dead Code elimination)过程处理掉。

运行如下命令来调用 Emscripten 进行编译:

$ emcc fibonacci.cpp -s WASM=1 -O3 --no-entry -o fibonacci.wasm

-s WASM=1 表明编译成 Webassembly 的程序,-O3 表明编译的优化程度,–no-entry 参数告诉编译器没有声明 main 函数,-o 指定生成的文件名。

我们看一下生成的字节码文件 fibonacci.wasm

image-20220704135901588.png

最开始的前八个字节 00 61 73 6D 01 00 00 00 表明当前是一个 wasm 的模块。

加载运行

新建一个 html 文件,通过VSCode的 Live Server 插件启动一个服务,加载 wasm 文件输出调用结果

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>斐波纳切数字</title>
</head>
<script>
  const response = fetch("fibonacci.wasm");
  WebAssembly.instantiateStreaming(response).then(
    ({ instance }) => {
      let { fibonacci } = instance.exports;
      console.log(fibonacci(30));
    }
  )
</script>

<body>
</body>

</html>

应用场景

WebAssembly 通常用于需要高性能的计算密集型应用程序。这些包括元宇宙相关技术 AR/VR 实时开发、视频编辑、VPN、图像识别等。要了解学习 wasm 的各种技术,请单击此处

在被浏览器广泛支持后,一些重量级的应用也逐渐移植到了Web上,包括:

  • Google Earth:一种主要基于卫星图像呈现地球 3D 表示的软件。
  • AutoCAD:计算机辅助设计和绘图软件应用程序,它是在带有内部图形控制器的微型计算机上运行的桌面应用程序。
  • TensorFlow:用于机器学习和人工智能的免费开源软件库。

局限性

虽然不断开发新功能,但 WebAssembly 的功能是有限的。

  • 没有垃圾收集:与采用垃圾回收的 JavaScript 不同,Wasm 使用平面/线性内存模型,在实例化时分配大量内存并且不会自动回收内存。

  • 不能直接访问DOM:WebAssembly 无法访问文档对象模型 (DOM),任何 DOM 操作都需要使用 JavaScript 间接完成。或者,在通过 JavaScript 胶水代码完成 DOM 操作的情况下,也可以使用任何工具链,例如 Emscripten。性能取决于所使用的库。

  • 不支持C/C++ DLL动态链接库:编译过程必须是源码,不能打包DLL,说明链接

参考资料

  1. MDN WebAssembly
  2. 快速认识 WebAssembly(2022.06.19)
  3. 快 11K Star 的 WebAssembly,你应该这样学(2021.09.29)
  4. 20分钟上手 WebAssembly(2018.08.20)
  5. WebAssembly 现状与实战(2018.06.13)
  6. 详解JavaScript引擎V8执行流程(2021.07.17)
  7. 什么是 WebAssembly(wasm)?(2021.06.25)