加载失败
本帖围绕一篇名为“Notes on Writing WASM”的文章及其评论展开,很多回复实际上是在讨论把 Rust/C++ 等语言编译到 WebAssembly 时的绑定、编码与工具链问题,而非手写原始 Wasm 二进制。讨论反复涉及历史与生态背景:asm.js 与 Emscripten(把 C/C++ 编译到 JS/WASM 的工具链)、wasm-bindgen/embind 这样的绑定工具的权衡,以及 Mozilla 倡导的 WASM Component Model(一个让 Wasm 直接调用高层 Web API 的提案)。技术前提包括字符串编码差异(JS 常用 UTF-16,Rust/Wasm 常用 UTF-8)、WASM 的 linear memory(线性内存)模型、WASI(WebAssembly System Interface)在服务端的角色,以及近期关于 WASM GC(垃圾回收)和跨界拷贝开销的争议。争论的核心是追求更原生的跨语言性能与更低的互操作复杂性之间的权衡:是继续依赖 JS glue,还是在浏览器/运行时层面增加复杂机制来简化绑定。
多位评论提到 Mozilla/Firefox 在推动将 Web APIs 直接暴露给 WASM 的早期提案(基于 WASM Component Model),目标是让 WebAssembly 在浏览器中成为一等公民并减少 JS shim。支持者认为这能降低唤醒 JS 引擎的开销、改善字符串编组性能并提升开发者体验,还能让不同语言通过高层接口互操作,避免把一切退回到 C 风格接口。反对者则指出 Component Model 会带来大量复杂性且收益有限:示例中的性能提升主要体现在字符串传输场景,并不能自动解决像 WebGPU 那类需要在 WGPUBuffer 与 JS ArrayBuffer 之间拷贝的大量数据通路问题。
评论普遍批评自动绑定工具(如 Emscripten 的 embind 或 wasm-bindgen)容易引入体积膨胀、复杂的 glue code 和调优难题,建议不要盲目自动映射复杂语言的原生类型。实务经验是采用混合式工程:把非琐碎工作放在手写的 JS/宿主中、或通过设计良好的 C API 隧道进行互操作,而不是把 C++/Rust 的大语义表面直接暴露到 JS。评论还指出 wasm-bindgen 曾有维护停滞的问题(影响体验),相比之下像 PyO3 在 Python 生态的工具链体验被认为更好,且有报道 2025 年起社区与公司(如 Cloudflare)开始推动相关工具的活跃度回升。
有人断言 WASM 使用者规模非常小、注定成为小众技术,但反方列举了多个现实落地的场景来反驳这一点。实用案例包括浏览器端将计算密集任务交给 WASM 的创意/生产力工具(如 Figma、Miro),以及后端/边缘把 WASM 当作沙箱或插件运行时(如 Istio、Helm、OPA);另有团队用 WASM 在浏览器部署机器学习模型。讨论还指出,若能实现更直接的 DOM 访问或减少 JS glue,某些用例会更容易采用,但当前跨界的字符串编码、内存拷贝等互操作成本仍然是阻力。
评论中关于 WASM GC 的讨论来自正在尝试基于 WASM GC 写语言的人与使用者,他们报告了具体设计权衡:WASM 的 GC 把 ref/struct/array 等类型交由运行时管理,vtable 实现较直接但接口设计受限,fat pointer/接口需要对象来表达。浏览器方面的好处是 GC 可以跨 DOM、JS 与 WASM 协作实现统一回收,但缺点是跨边界的数据传输需要更多拷贝——例如 GCed 字节数组对外不透明,需要提供逐字节访问或先拷贝到 linear memory;字符串处理尤为麻烦且多线程支持尚不足,部分提案(如 stringref)已停滞,WASI 向 GC 类型的 lowering 也在讨论之中。
多名开发者分享了不同语言在 WASM 上的实战体验:在游戏 jam 中 C++ 遇到 Emscripten 的编译 bug,Zig 在生态与文档上不足,Rust 因借用检查和严格编译带来学习与开发摩擦,而 Odin 在短期项目中体验良好。很多人因为互操作开销与绑定复杂性最终回退到 JS/TS,或选择在后端以 WASM 作为轻量沙箱;同时工具链(如 wasm2c/wasm2go)展示了 WASM 本身可以是较小的运行目标。评论还回顾了 asm.js 到 WebAssembly 的演进,解释了为何现在既有针对性能的设计,也有为 POSIX 仿真带来的 bloat 和不同用途的工具链分歧。
WASM Component Model: 一个旨在让 WebAssembly 能直接调用高层 Web API 的规范提案,目标是简化跨语言绑定、减少 JS shim 并改善类型与字符串互操作。
wasm-bindgen: Rust ↔ JavaScript 的绑定生成工具,用于把 Rust 类型与函数导出给 JS 使用;评论提到其维护活跃度直接影响开发体验。
Emscripten: 把 C/C++ 编译到 JavaScript 或 Wasm 的工具链,包含 embind 自动绑定与 POSIX 仿真,经常被指出会引入体积膨胀与运行时边界。
WASI(WebAssembly System Interface): 为 WebAssembly 在非浏览器环境提供系统调用抽象的接口层,类似 POSIX,用于文件、内存与资源访问;讨论中涉及 WASI preview 0.2 与向 GC 类型的 lowering。
linear memory(线性内存): WASM 的一块连续字节内存区域(linear memory),通常用于在 wasm 与宿主(JS/WASI)之间传输原始数据,并常作为跨界拷贝的桥梁。
WASM GC(Garbage Collection): WebAssembly 新增的垃圾回收支持,提供 ref/struct/array 等受 GC 管理的类型,但当前跨边界访问、字符串处理与多线程支持仍存在限制。
asm.js: 早期将 C/C++ 编译为高性能 JavaScript 子集的技术,是推动后来 WebAssembly 设计与演进的重要历史阶段。