WebAssembly简单入门

参考文档

wasm概念

什么是 WebAssembly?

WebAssembly (简称 Wasm) 是一种为网络设计的二进制指令格式,它提供了一种紧凑的二进制格式,使代码能以接近原生的速度运行在浏览器中。

核心特点

  • 高效执行:接近原生代码的执行速度
  • 安全沙盒:在隔离的环境中执行
  • 语言无关:可由多种编程语言编译生成
  • 平台无关:在所有现代浏览器中运行
  • 与 Web 平台兼容:可与 JavaScript 和 DOM 交互

wasm工具链

我们可以选用这些主流的工具链用于编写代码和编译wasm模块

  1. Emscripten:C/C++ 到 WebAssembly 的主流编译器
  2. Rust + wasm-pack:将 Rust 编译为 WebAssembly
  3. AssemblyScript:TypeScript 的严格子集,编译为 WebAssembly
  4. Go:支持编译为 WebAssembly
  5. wat2wasm:将文本格式转换为二进制格式

emcc简单入门

这里使用c + emcc简单入门wasm

我们以a+b的例子入门emcc编译wasm

首先编写c语言代码

C 复制代码
int add(int a, int b) {
    return a + b;
}

运行编译命令

Bash 复制代码
emcc add.c -O2 -s MODULARIZE=1 -s EXPORT_ES6=1 -s EXPORTED_FUNCTIONS='["_add"]' -o add.js

会得到一个胶水文件add.js和一个wasm模块

编写html文件

HTML 复制代码
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>emcc add demo</title>
  </head>
  <body>
    <script type="module">
      import CreateModule from "./add.js";
      const Module = await CreateModule();
      console.log(Module._add(5, 6));
    </script>
  </body>
</html>

在浏览器中运行

编译模式

emcc包括如下几种编译模式,

  1. 默认(js胶水文件 + .wasm
  • 命令示例:emcc add.c -O2 -s EXPORTED_FUNCTIONS='["_add"]' -o add.js
  • 使用:直接引用 add.js,等待 runtime 初始化后调用 Module._add 或 Module.ccall。
HTML 复制代码
<!doctype html>
<html>
<body>
<script src="./add.js"></script>
<script>
  Module.onRuntimeInitialized = () => {
    const r = Module._add(1, 2); // 或 Module.ccall('add', 'number', ['number','number'], [1,2])
    console.log('1+2=', r);
  };
</script>
</body>
</html>
  1. Standalone WASM(纯 wasm)
  • 命令示例:emcc add.c -O2 -s STANDALONE_WASM=1 -s EXPORTED_FUNCTIONS='["_add"]' -Wl,--no-entry -o add.wasm
  • 使用:用原生 WebAssembly.instantiateStreaming / instantiate 加载 exports.add。若 wasm 需要 WASI,请传入对应 imports(通常不需要如果按上面命令编译)。
HTML 复制代码
<!doctype html>
<html>
<body>
<script>
async function load() {
  const res = WebAssembly.instantiateStreaming
    ? await WebAssembly.instantiateStreaming(fetch('add.wasm'), {})
    : await WebAssembly.instantiate(await (await fetch('add.wasm')).arrayBuffer(), {});
  const { add } = res.instance.exports;
  console.log('1+2=', add(1,2));
}
load().catch(e => console.error(e));
</script>
</body>
</html>
  1. 单文件(SINGLE_FILE,把 wasm 内联到 add.js)
  • 命令示例:emcc add.c -O2 -s SINGLE_FILE=1 -s EXPORTED_FUNCTIONS='["_add"]' -o add.js
  • 使用:与默认相同,但不需要单独的 .wasm 文件(部署单文件方便)。
HTML 复制代码
<!doctype html>
<html>
<body>
<script src="./add.js"></script>
<script>
  Module.onRuntimeInitialized = () => {
    console.log(Module._add(3,4));
  };
</script>
</body>
</html>
  1. MODULARIZE(可多次实例化的 JS wrapper)
  • 命令示例:emcc add.c -O2 -s MODULARIZE=1 -s EXPORT_NAME='CreateModule' -s EXPORTED_FUNCTIONS='["_add"]' -o add.js
  • 使用:先加载脚本,再通过 CreateModule() 得到 Module 实例(返回 Promise)。
HTML 复制代码
<!doctype html>
<html>
<body>
<script src="./add.js"></script>
<script>
CreateModule().then(Module => {
  console.log('1+2=', Module._add(1,2));
});
</script>
</body>
</html>
  1. ES6 模块化(EXPORT_ES6 + MODULARIZE)
  • 命令示例:emcc add.c -O2 -s MODULARIZE=1 -s EXPORT_ES6=1 -s EXPORTED_FUNCTIONS='["_add"]' -o add.js
  • 使用:作为 ES 模块 import,适合现代打包器/浏览器。
HTML 复制代码
<!doctype html>
<html>
<body>
<script type="module">
import CreateModule from './add.js';
const Module = await CreateModule();
console.log(Module._add(5,6));
</script>
</body>
</html>

我们使用更适合ESM模块的模式即可

wasm-pack

我们使用wasm-pack的例子,创建一个示例项目 drager.github.io/wasm-pack/

wasm-pack 可以直接将 rust项目编译为 wasm的 npm包,在js中直接引入使用

  1. 运行 wasm-pack new hello-wasm
  2. cd hello-wasm
  3. 运行 wasm-pack build --target web
  4. 这个工具会在 pkg 目录中生成文件
  5. 导入它: import init, { greet } from "./pkg/hello_wasm.js" ,初始化它:await init(),然后使用它:greet()

在html文件中引入wasm

HTML 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script type="module">
    import init, { greet } from "./pkg/wpack_demo.js"
    await init()
    greet()
  </script>
</body>
</html>

就可以弹出alert

相关推荐
漂流瓶jz8 分钟前
Webpack中各种devtool配置的含义与SourceMap生成逻辑
前端·javascript·webpack
前端架构师-老李19 分钟前
React 中 useCallback 的基本使用和原理解析
前端·react.js·前端框架
木易 士心1 小时前
CSS 中 `data-status` 的使用详解
前端·css
明月与玄武1 小时前
前端缓存战争:回车与刷新按钮的终极对决!
前端·缓存·回车 vs 点击刷新
牧马少女1 小时前
css 画一个圆角渐变色边框
前端·css
zy happy1 小时前
RuoyiApp 在vuex,state存储nickname vue2
前端·javascript·小程序·uni-app·vue·ruoyi
小雨青年2 小时前
Cursor 项目实战:AI播客策划助手(二)—— 多轮交互打磨播客文案的技术实现与实践
前端·人工智能·状态模式·交互
小光学长2 小时前
基于Vue的儿童手工创意店管理系统as8celp7(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
前端·数据库·vue.js
meichaoWen2 小时前
【Vue】Vue框架的基础知识强化
前端·javascript·vue.js
jingling5552 小时前
Flutter | 基础环境配置和创建flutter项目
前端·flutter