WebAssembly-现代网络浏览器中的新型代码

image.png

WebAssembly 简介

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

它设计的最初目的不是为了手写代码而是为诸如 C、C++和Rust等底层源语言提供一个高效的编译目标。

WebAssembly或称wasm是一个低级编程语言。WebAssembly是便携式的抽象语法树,被设计来提供比JavaScript更快速的编译及执行。WebAssembly将让开发者能运用自己熟悉的编程语言(最初以C/C++作为实现目标)编译,再藉虚拟机引擎在浏览器内执行。WebAssembly的开发团队分别来自MozillaGoogleMicrosoftApple,代表着四大网络浏览器FirefoxChromeMicrosoft EdgeSafari。2017年11月,以上四个浏览器都开始实验性的支持WebAssembly。在 2019 年 12 月 5 日,W3C制定《WebAssembly 核心规范页面存档备份,存于互联网档案馆)》,WebAssembly 正式被认证为 Web 的标准之一。

WebAssembly 主要特点

高效且快速

Wasm 堆栈机器被设计为以大小和加载时间高效的二进制格式进行编码。 WebAssembly 旨在通过利用广泛平台上可用的通用硬件功能以本机速度执行。

安全

WebAssembly 描述了一个内存安全的沙盒执行环境,它甚至可以在现有的 JavaScript 虚拟机中实现。当嵌入到 Web 中时,WebAssembly 将强制执行浏览器的同源和权限安全策略。

开放且可调式

WebAssembly is designed to be pretty-printed in a textual format for debugging, testing, experimenting, optimizing, learning, teaching, and writing programs by hand. The textual format will be used when viewing the source of Wasm modules on the web.

WebAssembly 旨在以文本格式进行漂亮的打印,以用于调试、测试、实验、优化、学习、教学和手动编写程序。在网络上查看 Wasm 模块的源代码时将使用文本格式。

开放式web平台的一部分

WebAssembly is designed to maintain the versionless, feature-tested, and backwards-compatible nature of the web. WebAssembly modules will be able to call into and out of the JavaScript context and access browser functionality through the same Web APIs accessible from JavaScript. WebAssembly also supports non-web embeddings.

WebAssembly 旨在保持 web 的无版本、经过功能测试和向后兼容的特性。 WebAssembly 模块将能够调用和调用 JavaScript 上下文,并通过可从 JavaScript 访问的相同 Web API 访问浏览器功能。 WebAssembly 还支持非网络嵌入。

WebAssembly 应用场景

介绍一些适用webassmbly的场景

在线游戏

WebAssembly 的高性能和低延迟使其成为在线游戏的理想选择。游戏开发者可以将已有的 C/C++ 代码编译成 WebAssembly 格式并在 Web 上运行,从而实现更流畅、更快速的游戏体验。

  • 视频与音频的编解码器(Codecs)、定制化的数据压缩、3D模型;

WebAssembly 可以执行高效的计算任务,因此可以用于实现视频和音频的编解码器(Codecs)、数据压缩和 3D 模型等计算密集型任务。

  • 媒体编辑工具;

由于 WebAssembly 具有原生代码的高性能和低延迟特性,因此可以用于开发媒体编辑工具,如音视频编辑器、图像处理器等。

WebAssembly 可以用于执行语音合成和语音识别等计算密集型任务,这些任务通常需要高效的计算能力。

WebAssembly 可以用于客户端的计算机视觉应用程序,如图像识别、人脸识别、目标跟踪等。

  • 将现有的胖客户端(应用程序)移植到Web平台;

WebAssembly 可以将已有的 C/C++ 等语言编写的应用程序移植到 Web 平台上,从而实现跨平台的运行。

  • 任何需要在用户终端以极致速度运行的程序。

WebAssembly 可以执行高效的计算任务,因此可以用于任何需要在用户终端以极致速度运行的程序。例如,可以用 WebAssembly 开发高性能的图像处理、物理模拟、数学计算等应用程序。

嵌入式系统:wasm可以让嵌入式系统应用程序在不同的硬件和操作系统中运行,提高兼容性和效率。例如,可以使用wasm来实现物联网设备,智能合约,区块链等功能

WebAssembly 的运行原理

浏览器工作原理

JavaScript运行原理

JavaScript引擎是一种实现JavaScript语言的解释器或编译器,它负责解释和执行JavaScript代码,实现网页的动态交互和功能。以下是JavaScript引擎的一些核心概念和技术:

  1. 解释器和编译器:JavaScript引擎通常包含解释器和编译器两个部分。解释器可以快速解释和执行JavaScript代码,但是性能较低;编译器可以将JavaScript代码编译为机器码,实现更高的性能,但是需要额外的编译时间和空间。
  2. JIT编译:JavaScript引擎通常采用JIT(Just-In-Time)编译技术,将JavaScript代码编译为本地机器码,并缓存编译结果,以提高代码执行的性能。
  3. 内存管理:JavaScript引擎需要负责管理内存的分配和释放,避免内存泄漏和内存溢出等问题。
  4. 优化技术:JavaScript引擎通常采用多种优化技术,例如内联缓存、代码消除、循环展开等,以提高代码的执行效率和响应速度。
  5. 跨平台支持:JavaScript引擎需要支持多种平台和操作系统,例如浏览器、移动设备等。

常见的JavaScript引擎包括V8、SpiderMonkey、JavaScriptCore等。其中,V8是Google开发的JavaScript引擎,在Chrome浏览器中得到广泛应用,具有高性能和低内存占用的特点。
总之,JavaScript引擎是实现JavaScript语言的核心技术之一,它的性能和功能对于网页的交互和用户体验至关重要。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
+-------------------------+
| 代码输入 |
+-------------------------+
|
v
+-------------------------+
| 词法分析(Lexing) |
+-------------------------+
|
v
+-------------------------+
| 语法分析(Parsing) |
+-------------------------+
|
v
+-------------------------+
| 生成AST(Abstract |
| Syntax Tree) |
+-------------------------+
|
v
+-------------------------+
| 生成字节码 |
+-------------------------+
|
v
+-------------------------+
| JIT编译器 |
+-------------------------+
|
v
+-------------------------+
| 生成机器码 |
+-------------------------+
|
v
+-------------------------+
| 代码执行 |
+-------------------------+
代码输入:JavaScript引擎接收JavaScript代码作为输入。

词法分析:JavaScript引擎将代码分解为一系列的token,每个token表示一个词法单元,例如关键字、运算符、变量名等。

语法分析:JavaScript引擎将token流转换为抽象语法树(AST),表示代码的语法结构和逻辑。

生成字节码:JavaScript引擎将AST转换为字节码,这是一种中间形式的代码表示,用于优化和执行。

JIT编译器:JavaScript引擎使用JIT编译器将字节码编译为本地机器码,以提高代码的执行效率和响应速度。

生成机器码:JavaScript引擎将编译后的机器码存储在内存中,用于后续的代码执行。

代码执行:JavaScript引擎执行机器码,实现代码的动态交互和功能。


webassmbly运行原理

WebAssembly 之所以比 JavaScript 更高效,是因为它的设计和实现可以更好地利用计算机硬件的特性。

WebAssembly 是一种低级字节码格式,它的指令集是基于栈的,可以直接映射到底层硬件的指令集,从而实现更好的性能。与之相比,JavaScript 是一种高级语言,其代码需要经过解释器的解释和执行,还需要进行垃圾回收、动态类型检查等操作,这些都会带来一定的性能开销。
另外,WebAssembly 还提供了一些优化的特性,如本地变量、线性内存等,可以使得代码的性能更加高效。WebAssembly 的线性内存模型允许程序直接访问内存,而不需要通过 JavaScript 中的 ArrayBuffer 对象等中间层,从而避免了不必要的拷贝操作,提高了内存访问的效率。
此外,WebAssembly 还支持多线程,并提供了原子操作和共享内存等机制,可以更好地利用现代计算机的多核心处理能力,实现并行计算,进一步提高程序的性能。
相比之下,JavaScript 的架构主要是基于事件循环的,通过事件循环机制实现异步编程,避免了阻塞主线程,提高了程序的响应性。但是,由于 JavaScript 是一种高级语言,其代码需要经过解释器的解释和执行,因此在性能上不如 WebAssembly。同时,JavaScript 的内存管理由垃圾回收器负责,会带来一定的运行时开销。此外,JavaScript 并不直接支持多线程,虽然可以通过 Web Workers 等机制实现并发,但是相对来说还是比较复杂和低效的。
综上所述,WebAssembly 通过优化其设计和实现,可以更好地利用计算机硬件的特性,从而实现更高效的性能。而 JavaScript 则主要是通过事件循环机制实现异步编程,提高程序的响应性,但在性能上不如 WebAssembly。

对比

webassembly和js的运行原理有以下几点不同:

  • webassembly的字节码和底层机器码很相似,可以快速地被浏览器解码和验证,并且不需要进行额外的优化。js则需要经过多个步骤才能转换成机器码,例如词法分析,语法分析,抽象语法树生成,字节码生成,即时编译和优化等。
  • webassembly是一种静态类型的语言,它的数据类型和内存布局都是在编译时确定的,并且可以直接操作内存。js则是一种动态类型的语言,它的数据类型和内存管理都是在运行时确定的,并且需要通过垃圾回收机制来释放内存。
  • webassembly可以利用多种语言的特性和优势,例如C/C++的底层性能和Rust的内存安全等。js则只能使用JavaScript提供的功能和API。

综上所述,wasm比js高效的原因主要有以下几点:

  • wasm可以更快地被浏览器加载和执行,减少了网络传输和解析编译的时间。
  • wasm可以更直接地访问和操作内存,提高了运行时的性能。
  • wasm可以使用多种语言编写,充分利用各种语言的优势

WebAssembly 的生态系统

  • 云原生组件
  • is

WebAssembly 的相关案例

  • Figma:这是一个在线的设计和协作平台,它使用wasm来实现高性能的图形渲染和编辑功能,并且可以在不同的浏览器和设备上运行
  • Squoosh:这是一个在线的图片压缩和转换工具,它使用wasm来实现多种图片格式的编解码,并且可以在浏览器中快速处理大量的图片
  • AutoCAD:这是一个著名的三维建模和设计软件,它使用wasm来实现在浏览器中运行AutoCAD的核心引擎,并且可以提供与桌面版相同的功能和体验
  • Nginx:这是一个著名的web服务器和反向代理软件,它使用wasm来实现动态加载和执行自定义的扩展模块,并且可以提高性能和灵活性。
  • TensorFlow:这是一个流行的机器学习平台,它使用wasm来实现在浏览器中运行TensorFlow Lite模型,并且可以利用SIMD和多线程等特性。
  • Istio是一个用于服务网格的开源平台,它可以使用WebAssembly(Wasm)来扩展Istio服务代理(Envoy代理)的功能。Wasm是一种沙箱技术,可以用不同的编程语言来构建新的协议、自定义指标、日志和其他过滤器。

WebAssembly 的简单实践

支持wasm的编程语言,以及它们的一些特点

  • C/C++:这是最早也是最广泛支持wasm的编程语言,它可以使用Emscripten工具链来编译成wasm模块,并且可以直接操作内存和底层性能。
  • Rust:这是一种现代的系统编程语言,它也可以使用Emscripten或其他工具来编译成wasm模块,并且可以提供内存安全和并发支持。
  • C#:这是一种面向对象的编程语言,它可以使用Mono或Blazor框架来编译成wasm模块,并且可以利用.NET平台的功能和库。
  • Python:这是一种解释型的脚本语言,它可以使用Pyodide或其他工具来将Python解释器编译成wasm模块,并且可以执行.py文件。
  • Qt:这是一个跨平台的图形用户界面框架,它可以使用Qt for WebAssembly来编译成wasm模块,并且可以在浏览器中运行Qt应用程序。
  • AssemblyScript:这是一种基于TypeScript的编程语言,它可以使用Binaryen工具链来编译成wasm模块,并且可以和JavaScript互操作。

为什么选择使用Rust来写WebAssembly ?

选择 Rust 来编写 WebAssembly(WASM)主要有以下几个优点:

  1. 安全性 Rust 作为一种系统级编程语言,具有强大的类型系统和所有权模型,可以在编译期间捕获大部分常见的内存安全问题,避免了许多运行时错误,从而提高了代码的安全性和可靠性。这一点对于 WebAssembly 来说尤其重要,因为 WebAssembly 运行在一个相对不安全的环境中,可能面临来自恶意代码和攻击的风险。
  2. 性能 Rust 作为一种系统级编程语言,具有非常高的性能和低的内存占用率,这使得 Rust 可以轻松地生成高效的 WebAssembly 代码。同时,Rust 还支持多线程和并发编程,可以利用 WebAssembly 的并行执行特性,进一步提高程序的性能。
  3. 易于与 WebAssembly 集成 Rust 对 WebAssembly 有良好的支持,Rust 编译器可以将 Rust 代码编译成 WebAssembly 二进制文件,并提供了一些工具和库,可以方便地将 Rust 代码和 JavaScript 代码进行集成。这使得 Rust 成为一种非常适合编写 WebAssembly 应用程序的编程语言。
  4. 社区支持 Rust 是一个非常活跃的开源社区,拥有丰富的第三方库和工具,可以方便地实现各种功能。同时,Rust 社区也积极支持 WebAssembly 技术的发展,为 Rust WebAssembly 开发提供了良好的支持和资源。

构建简单组件

1
cargo install wasm-pack

创建一个项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[package]
name = "rust-wasm"
version = "0.1.0"
edition = "2021"
authors = ["麦奇 <biaogejiushibiao@outlook.com>"]
description = "A sample project with wasm-pack"
license = "MIT/Apache-2.0"
repository = "https://github.com/ken-xue/rust-wasm"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2"
console_error_panic_hook = "0.1"

[target.'cfg(target_arch = "aarch64")']
rustflags = [
"-C", "link-arg=-s",
"-C", "link-arg=--no-entry",
]
1
2
3
4
5
6
7
8
9
// 将计算斐波那契数列的递归函数暴露给 JavaScript
#[wasm_bindgen]
pub fn calc_fib(n: i32) -> i32 {
// let start_time = Instant::now();
let result = fib(n);
// log_duration(start_time, &format!("Calculated fib({})", n));
result
}

1
wasm-pack build --target web

编译完成后的包我们同样可以发布到npm服务器上提供下载使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8" />
<title>hello-wasm example</title>
</head>
<body>
<script type="module">
import init, {calc_fib} from "./pkg/rust_wasm.js";
init().then(() => {
// greet("WebAssembly");
// 开始计时
const st = performance.now();
const ret = calc_fib(40)
// 结束计时
const et = performance.now();
// 计算执行时间
const edt = et - st;
console.log(`rust-wasm 代码执行时间为 ${edt} 毫秒 ${ret}`);

});

</script>
<script>
// 开始计时
function fib(n) {
if (n == 1 || n == 0) {
return n
}
return fib(n-1) + fib(n-2)
}
const st = performance.now();
const fret = fib(40)
// 结束计时
const et = performance.now();
// 计算执行时间
const edt = et - st;
console.log(`js代码执行时间为 ${edt} 毫秒 ${fret}`);
</script>
</body>
</html>

测试结果
image.png
可以看到在同样进行计算fib(40)使用wasm的耗时与原生js相比几乎快了一倍

构建完整应用

整个 Web 应用都基于 Rust 开发

  1. Yew:一款现代化的Rust WebAssembly框架,使用类似于React的组件模型,用于构建动态的Web前端应用程序。
  2. Seed:一个Rust和WebAssembly的框架,用于构建Web前端应用程序,包含类似于React的组件和虚拟DOM。
  3. wasm-bindgen:一个用于编写Rust和JavaScript之间的接口的库,使得使用WebAssembly成为Web应用程序的一部分变得更容易。

WebAssembly 的总结与展望

WebGPU是一种新的标准化的图形硬件接口,它可以让WebAssembly访问GPU的功能和资源。WebAssembly和WebGPU可以结合使用,实现高效的图形渲染和计算

WebAssembly 的相关资料

  1. 官网:https://developer.mozilla.org/en-US/docs/WebAssembly
  2. 快速开始:https://webassembly.org/getting-started/developers-guide/
  3. Rust Wasm: https://developer.mozilla.org/en-US/docs/WebAssembly/Rust_to_wasm
  4. https://github.com/juj/wasm_webgpu
  5. https://wapm.io/

WebAssembly-现代网络浏览器中的新型代码
https://mikeygithub.github.io/2023/04/08/yuque/WebAssembly-现代网络浏览器中的新型代码/
作者
Mikey
发布于
2023年4月8日
许可协议