WebAssembly 上手入门

446 阅读3分钟

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 环境准备

  1. 确保已安装 Node.js(方便进行 WebAssembly 文件的构建与测试)。
  2. 安装 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 具有高性能、跨平台、多语言的特性,适用于性能要求高、需要复用原生代码的场景,未来有望在更多领域发挥重要作用。