WebAssembly 与 TypeScript:高级集成技术

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

WebAssembly 与 TypeScript 高级集成简介



WebAssembly (Wasm) 彻底改变了 Web 开发,使得在浏览器中能够以接近原生的速度执行代码。然而,在高级层面,开发者面临一个挑战:如何将 TypeScript 的强类型与 Wasm 的低级能力有效结合?在本文中,我们将探讨超越基础示例的技术:手动内存管理、创建完全类型化的包装器、调用优化以及复杂项目的构建。



本文面向已熟悉 Wasm 和 TypeScript 基础的开发者。我们不会停留在“Hello World”的编译上——而是聚焦于实际问题:缓冲区操作、数据结构、多线程和性能分析。



1. 高级内存管理:手动分配与结构体



从 Wasm 导出函数到 TypeScript 的基础示例通常处理原始类型。在高级层面,您需要传递复杂数据:字符串、结构体数组、图像。我们来看看如何通过 WebAssembly.Memory 实现。



1.1. 内存分配与释放



假设我们有一个用 AssemblyScript 或 C 编写的 Wasm 模块,它导出了 malloc 和 free 函数。在 TypeScript 中,我们创建一个包装器:



// types.tsexport interface WasmMemory {  malloc(size: number): number;  free(ptr: number): void;  memory: WebAssembly.Memory;}

// memory-manager.tsexport class MemoryManager { private wasm: WasmMemory;

constructor(wasm: WasmMemory) { this.wasm = wasm; }

allocateString(str: string): number { const encoder = new TextEncoder(); const bytes = encoder.encode(str); const ptr = this.wasm.malloc(bytes.length + 1); // +1 用于空终止符 const view = new Uint8Array(this.wasm.memory.buffer); view.set(bytes, ptr); view[ptr + bytes.length] = 0; // 空终止符 return ptr; }

readString(ptr: number): string { const view = new Uint8Array(this.wasm.memory.buffer); let end = ptr; while (view[end] !== 0) end++; const bytes = view.slice(ptr, end); return new TextDecoder().decode(bytes); }

freeString(ptr: number): void { this.wasm.free(ptr); }}


这种方法确保内存不会泄漏,并且 TypeScript 完全控制数据的生命周期。



1.2. 数据结构操作



要传递对象(例如,坐标为 {x: f32, y: f32} 的点),请使用 DataView:



interface Point { x: number; y: number; }

export class PointManager { private wasm: WasmMemory; private readonly SIZE = 8; // 2 个 float32

constructor(wasm: WasmMemory) { this.wasm = wasm; }

createPoint(p: Point): number { const ptr = this.wasm.malloc(this.SIZE); const view = new DataView(this.wasm.memory.buffer); view.setFloat32(ptr, p.x, true); view.setFloat32(ptr + 4, p.y, true); return ptr; }

readPoint(ptr: number): Point { const view = new DataView(this.wasm.memory.buffer); return { x: view.getFloat32(ptr, true), y: view.getFloat32(ptr + 4, true) }; }}


重要提示:始终检查内存对齐。Wasm 要求 f32 按 4 字节对齐。



2. Wasm 导入和导出在 TypeScript 中的类型化



没有类型化,使用 Wasm 是危险的:您可能将一个数字作为指针传递,导致段错误。请使用严格的接口。



2.1. 从 Wasm 生成类型



工具 wasm-objdump 或 wasm2wat 可以获取函数签名。对于 AssemblyScript 项目,请使用类型生成器:



// wasm-types.d.tsdeclare namespace WasmModule {  interface Exports {    add(a: number, b: number): numb                

博客

书籍推荐