WebAssembly 入门

2023-09-19 pv

这是一篇简单介绍 WebAssembly 的文章。文章里不会涉及太多关于底层实现的细节,因为我也是刚开始接触这个领域。

文章将主要分为三个部分:

  • WebAssembly 是什么
  • 被设计用来解决什么问题
  • 如何有效地使用

素材来源不仅限于官方文档,还有 YouTube 上一些精彩的分享。这些都将列在尾部的参考中。

1. WebAssembly 是什么

按照 官网🔗 官网说法,

WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable compilation target for programming languages, enabling deployment on the web for client and server applications.

首先,它是个二进制指令格式,其次是基于栈的虚拟机,同时为多种不同编程语言生成可移植目标,并且可以在客户端和服务端上部署

初衷就是为了统筹 Native 的效率和 Web 的通用性。

特性主要有四个:

  • 性能和速度
  • 安全
  • 开放和可调试
  • 开放 Web 平台组件

简而言之,WebAssembly 是为了将一些 Native 端才有的能力,比如已有的库,高性能应用等,移植到 Web 端。

试想,如果未来所有的原生应用都消失,用户所有需求都可以借助一个浏览器满足。那么浏览器即是下一代的操作系统,此言非虚。

2. WebAssembly 的发展史

任何技术都不是无缘无故发生。

WebAssembly 的诞生,本是为了解决 JavaScript 既有的一些问题。

V8 引擎在 2008 年的时候被首次引入到 Chrome,利用即时编译(Just-in-time Compilation, JIT)等技术,极大提高了 JavaScript 这门脚本语言的执行效率。

但人的野心无限。

有人就想,能不能让 JavaScript 以一种类似 Native code 的效率运行?

于是 Native Client (NaCI)🔗 Native Client (NaCI)技术于 2008 年被 Google 的 Brad Chen, Bennet Yee 和 David Sehr 提出。后来为了移植性,又搞出了 Portable Native Client (PNaCI)。

基本的原理可见下图,由于 NaCI 本身就是个比较复杂的技术,这里不展开。

简单来说,NaCI 有自己的 runtime,运行在独立的进程中,通过一系列接口和外界交互。

asm.jsEmscripten则是走了另外一条路。

直接将 C++ 等 Native 语言,编译成 JavaScript。其中,asm.js 是一种低级的 JavaScript 子集,目标是提高运行效率;Emscripten 是一个工具链,将 C/C++ 等代码编译成 asm.js。

据当时的测试,性能提升明显。

看起来已经很好了,但是还不够

因为首先,相比于紧凑的二进制格式,asm.js 需要解析,解析就需要耗费时间,因此 asm.js 存在冷启动的问题;另外,asm.js 仍然是一个比较 hack 的解决方案,只能解决部分问题。

于是在 2015 年,WebAssembly 诞生。

结合了 NaCI 和 asm.js 两者的优点。

一方面,它很像 NaCI,不是基于 JavaScript,而是一个全新的、经过正确设计、同时以二进制编码的指令集合

另一方面,它又很像 asm.js,运行在 Render 进程里。

工具链主要有两个:

  • Emscripten,但是编译产出结果是 WebAssembly,而不是 asm.js
  • 一个新的 LLVM WebAssembly 后端,可以这么理解,LLVM 将所有的语言都编译成一个中间语言(LLVM IR),后端需要做的,就是将 LLVM IR 转换成另一门语言,这里是 WebAssembly

尽管 WebAssembly 诞生还不到 10 年,仍然在发展,但最新的浏览器已经支持了很多新特性。

3. 如何开始

先看一个简单的例子。

假如我们有一个用 C/C++ 写的模块,经过一系列处理,就可以实现在浏览器中调用。

测试用的是 Ubuntu 系统。

先安装emcc环境。

hello.cc内容为:

#include <iostream>
int main() {
std::cout << "hello world" << std::endl;
return 0;
}

使用emcc编译:

Terminal window
$ emcc hello.cc -o hello.html

也可以:

Terminal window
emcc hello.cc -o hello.{js/wasm}

其中:

  • wasm是二进制的 Wasm 模块
  • js是一个包含胶水层的 JavaScript 文件,将原生的函数翻译成 js 函数
  • html可理解为一个测试用网页,实例化 Wasm 代码,然后展示结果

4. 总结

本文只是简单介绍了 WebAssembly 技术产生的背景,以及发展过程,最后提供了一个简单的 example 供测试。

从某些方面看,WebAssembly 并没有什么黑魔法,它只是将代码以一种更容易被优化的方式呈现,峰值的性能和原始 JavaScript 差异不大,只是 WebAssembly 平均效率会高一些

(完)

参考

  1. What is WebAssembly and where did it come from?🔗
  2. History of WebAssembly (Chrome University 2019)🔗
  3. WebAssembly for Web Developers (Google I/O ’19)🔗
  4. WebAssembly 官网🔗
  5. Mozilla WebAssembly🔗
在 GitHub 上编辑本页面

最后更新于: 2024-06-14T07:17:44+08:00