1. 什么是 WebAssembly?
WebAssembly(简称 WASM)是一种可以在现代 Web 浏览器中运行的二进制格式。它是一种与平台无关的低级语言,旨在提供接近原生性能的执行速度,主要用于提升 Web 应用的性能,支持多种编程语言(如 C、C++、Rust 等)编译成 WebAssembly 代码,运行在浏览器中。
1.1 WebAssembly 的特点
- 高性能:接近原生速度的执行性能,适合计算密集型任务。
- 多语言支持:支持 C、C++、Rust、Go 等语言编译为 WASM。
- 跨平台:同一份代码可以在不同的操作系统和浏览器中运行。
- 安全性:通过浏览器沙箱环境隔离,增强了执行代码的安全性。
- 模块化:支持模块化加载,便于代码拆分和复用。
1.2 WebAssembly 的应用场景
- 性能要求高的应用:如游戏、图像处理、音视频编码、3D 渲染等。
- 现有代码复用:将已有的 C、C++ 库移植到 Web 环境。
- 多语言支持:结合 JavaScript 进行复杂应用开发。
2. WebAssembly 入门实践
2.1 环境准备
- 确保已安装 Node.js(方便进行 WebAssembly 文件的构建与测试)。
- 安装 Emscripten 工具链(C/C++ 编译为 WebAssembly 的工具)。
# 安装 Emscripten
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh
2.2 编写第一个 WebAssembly 程序
1. 编写 C 语言代码
创建一个 hello.c 文件,代码如下:
#include <stdio.h>
int main() {
printf("Hello, WebAssembly!\n");
return 0;
}
2. 编译为 WebAssembly
使用 Emscripten 工具链将 C 代码编译为 WASM 文件。
emcc hello.c -o hello.html
该命令会生成以下文件:
hello.html:用于测试 WebAssembly 的 HTML 页面。hello.js:WebAssembly 模块的加载器。hello.wasm:编译后的 WebAssembly 文件。
3. 运行 WebAssembly
使用简单的 HTTP 服务器运行:
npx http-server
在浏览器中访问 http://localhost:8080/hello.html,即可看到 "Hello, WebAssembly!" 输出。
2.3 使用 WebAssembly 与 JavaScript 交互
1. 修改 C 代码
更新 hello.c,增加与 JavaScript 的交互:
#include <emscripten/emscripten.h>
EMSCRIPTEN_KEEPALIVE
int add(int a, int b) {
return a + b;
}
2. 编译并生成 WebAssembly
emcc hello.c -o hello.js -sEXPORTED_FUNCTIONS='["_add"]' -sEXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]'
3. 在 HTML 文件中加载并调用 WebAssembly
<!DOCTYPE html>
<html lang="en">
<head>
<title>WebAssembly Demo</title>
</head>
<body>
<h1>WebAssembly 加法示例</h1>
<script src="hello.js"></script>
<script>
Module.onRuntimeInitialized = () => {
const add = Module.cwrap('add', 'number', ['number', 'number']);
console.log('1 + 2 =', add(1, 2));
};
</script>
</body>
</html>
在浏览器控制台可以看到输出 1 + 2 = 3。
2.4 JavaScript 调用 C++
1. 编写 C++ 代码
创建 math.cpp 文件,代码如下:
#include <emscripten/emscripten.h>
extern "C" {
EMSCRIPTEN_KEEPALIVE
int multiply(int a, int b) {
return a * b;
}
}
2. 编译为 WebAssembly
emcc math.cpp -o math.js -sEXPORTED_FUNCTIONS='["_multiply"]' -sEXPORTED_RUNTIME_METHODS='["cwrap"]'
3. 调用 C++ 函数
在 HTML 文件中:
<script src="math.js"></script>
<script>
Module.onRuntimeInitialized = () => {
const multiply = Module.cwrap('multiply', 'number', ['number', 'number']);
console.log('3 * 4 =', multiply(3, 4));
};
</script>
2.5 C++ 调用 JavaScript
1. 修改 C++ 代码
更新 math.cpp,调用 JavaScript:
#include <emscripten/emscripten.h>
#include <emscripten/bind.h>
extern "C" {
EMSCRIPTEN_KEEPALIVE
void call_js() {
emscripten_run_script("console.log('Hello from C++!')");
}
}
2. 编译为 WebAssembly
emcc math.cpp -o math.js -sEXPORTED_FUNCTIONS='["_call_js"]' -sEXPORTED_RUNTIME_METHODS='["ccall"]'
3. 在 JavaScript 中执行
<script src="math.js"></script>
<script>
Module.onRuntimeInitialized = () => {
Module.ccall('call_js');
};
</script>
此代码将在浏览器控制台输出:Hello from C++!
3. WebAssembly 生态工具
- Emscripten:C/C++ 到 WebAssembly 的编译工具。
- wasm-pack:用于将 Rust 代码编译为 WebAssembly。
- AssemblyScript:使用 TypeScript 编写 WebAssembly。
- Binaryen:WebAssembly 优化和工具链。
4. 总结
本文介绍了 WebAssembly 的基本概念、环境搭建、C/C++ 代码编译为 WebAssembly,以及与 JavaScript 双向交互的示例。WebAssembly 具有高性能、跨平台、多语言的特性,适用于性能要求高、需要复用原生代码的场景,未来有望在更多领域发挥重要作用。