兰 亭 墨 苑
期货 · 量化 · AI · 终身学习
首页
归档
编辑文章
标题 *
URL 别名 *
内容 *
(支持 Markdown 格式)
WebAssembly(Wasm)与 JavaScript 的关系,最像“高性能模块 + 胶水与UI”的分工协作。Wasm 提供接近本地的算力,JS 负责加载、绑定、事件、DOM 与生态集成。核心协同点如下: 一、各自角色 - JavaScript - 宿主与编排:加载 Wasm、传参、接收返回值、处理事件与 DOM。 - 生态桥:与框架、网络、存储、UI 库对接。 - WebAssembly - 算力密集任务:数值计算、编解码、图像/音视频处理、加密、游戏物理。 - 可被多语言编译产出(C/C++/Rust/Go/…),在浏览器和很多非浏览器环境运行。 二、如何互相调用 - JS 调 Wasm - 通过 WebAssembly.instantiate(Streaming) 加载 .wasm,得到 exports,直接调用导出函数。 - Wasm 调 JS - 通过 importObject 把 JS 函数作为“导入”提供给 Wasm,在 Wasm 内调用这些函数(称为 host functions)。 三、内存与数据交换 - 共享线性内存:Wasm 有一块 ArrayBuffer(WebAssembly.Memory),JS 可通过 TypedArray 视图读写它。 - 简单标量直传:i32、i64(部分环境)、f32、f64 可作为参数/返回值直接传递。 - 复杂数据需编码: - 文本:UTF-8 编/解码,把字符串拷贝进 Wasm 内存,并传递指针+长度。 - 结构体/数组:在 Wasm 侧定义布局,JS 按偏移写入。 - 工具链简化: - Emscripten(C/C++)提供 ccall/cwrap、FS、UTF8 编码工具,自动生成 JS 绑定。 - Rust 的 wasm-bindgen + wasm-pack 可自动生成类型转换与 JS 绑定,支持直接传/返字符串、数组,甚至与 Web API 交互。 四、加载与初始化路径(最简示例) ```js // 假设有 add(i32,i32)->i32 的导出 const imports = { env: { log: (x) => console.log('Wasm says:', x) } }; const { instance } = await WebAssembly.instantiateStreaming(fetch('/module.wasm'), imports); // 若服务器不带正确 MIME,可用 fetch -> arrayBuffer -> instantiate const { add } = instance.exports; console.log(add(2, 40)); // 42 ``` 五、字符串传递(手动编码示意) ```js // Wasm 导出 alloc(len) 和 process(ptr,len),并在同一 Memory 上 const { memory, alloc, process } = instance.exports; const enc = new TextEncoder(), dec = new TextDecoder(); function callProcess(str) { const bytes = enc.encode(str); const ptr = alloc(bytes.length); new Uint8Array(memory.buffer, ptr, bytes.length).set(bytes); const outPtr = process(ptr, bytes.length); // 假设返回新串指针,长度另有方式返回 // 实务中常用返回值结构体或全局“out_len” } ``` 六、Rust 生态的“零样板”式协作 - Cargo.toml + wasm-bindgen 注解后,JS 可像调用普通函数一样: - Rust ```rust use wasm_bindgen::prelude::*; #[wasm_bindgen] pub fn greet(name: &str) -> String { format!("Hello, {name}!") } ``` - JS ```js import init, { greet } from './pkg/my_wasm.js'; await init(); // 加载 .wasm console.log(greet('Wasm')); ``` - wasm-bindgen 还能让 Rust 直接调用 Web API(如 window.fetch、Canvas、WebGL)而无需手写 importObject。 七、与 Web API 协同的常见模式 - 数据在 Wasm 中算,结果在 JS 中渲染 DOM/Canvas/Three.js。 - 使用 OffscreenCanvas 或 Web Workers: - 把 Wasm 放进 Worker,主线程保持流畅 UI。 - 通过 postMessage 传输 ArrayBuffer(零拷贝转移)以降低传输成本。 八、性能要点与坑 - 调用边界成本:JS↔Wasm 的函数频繁往返有开销。策略是“批量化”:用少量调用处理大块数据。 - 拷贝与编码成本:字符串和对象序列化/拷贝昂贵,能用共享内存(TypedArray)就用共享内存。 - 内存增长:Wasm Memory 扩容会导致 buffer 失效,需要重新获取视图。 - 异常与调试:Wasm 不直接抛 JS 异常;用工具链提供的调试符号、console/log 桥。 - GC 集成:目前 Wasm 无内建 GC(有提案进展),与 JS 对象互操作需要绑定工具或手动管理生命周期。 九、什么时候该引入 Wasm - 是:热点循环、DSP、压缩/解压、图像滤镜、向量/矩阵、密码学、PDF/字体解析、小游戏引擎核心。 - 否:主要是业务逻辑、DOM 编排、网络与状态管理,JS/TS 更合适。 十、端到端的协作范式 - JS 负责:加载/初始化、事件与 UI、调度、与平台 API 对接、把数据喂给 Wasm。 - Wasm 负责:计算密集核,暴露少量、稳定的函数接口。 - 数据通路:大块二进制经 TypedArray;高层对象在边界序列化;减少往返次数;必要时用 Worker。
配图 (可多选)
选择新图片文件或拖拽到此处
标签
更新文章
删除文章