WebAssembly 和 JavaScript 的 String 类型数据交换
前言
我们知道 WASM 和 HOST 环境(Browser)是通过线型内存共享空间的,所以本质上交换数据就是在这段共享内存中存和取数据,以及对数据如何编码。
这里又涉及到对应的 WASM 产物是如何在内存中存放数据的,例如下面的案例是在内存空间直接寻址提取和存放数据的
不同的数据结构(Array,Object,Struct)有自己的内存空间定义,所以我只针对 String 做 Case
字符串类型
wasm 到 js
index.c: 其中定义 get_str_from_wasm 方法,返回字符串指针
// wasm string pointer char * get_str_from_wasm(void) { return (char *)"Hello, From WASM"; }
Makefile: 编译
main: emcc \ index.c \ -s ERROR_ON_UNDEFINED_SYMBOLS=0 \ -s EXPORTED_FUNCTIONS="[_malloc,_free,_get_str_from_js]" \ --no-entry \ -o \ ./index.wasm clean: rm -rfv *.wasm
index.html: 加载 wasm,通过1byte(8Bit)去取内存数据
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Shared</title> </head> <script type="text/javascript"> (async function () { function AsciiToString(ptr, heapu8) { let str = ''; while (1) { let ch = heapu8[ptr++]; if (!ch) return str; str += String.fromCharCode(ch); } } const resp = await fetch(`./index.wasm?t=${Date.now()}`); const bytes = await resp.arrayBuffer(); const { instance } = await WebAssembly.instantiate(bytes, { env: {}, }); // 结构化数据 const HEAP8 = new Int8Array(instance.exports.memory.buffer); // get string from wasm const wasm_str_ptr = instance.exports.get_str_from_wasm(); const wasm_str = AsciiToString(wasm_str_ptr, HEAP8); console.log(wasm_str); //Hello, From WASM })().catch(err => console.error(err)); </script> </body> </html>
我只用 ascii 码的形式去编码数据和解码数据,其实如果涉及到 UTF-8 类型数据,需要用 Int32Array 去取数据解码。
js 到 wasm
index.c: 定义 set_str_from_js 来设置字符串,get_str_from_js 来去字符串指针
char * js_str; // set string pointer void set_str_from_js(char * str) { js_str = str; } // return string pointer char * get_str_from_js() { return js_str; }
Makefile
main: emcc \ index.c \ -s ERROR_ON_UNDEFINED_SYMBOLS=0 \ -s EXPORTED_FUNCTIONS="[_malloc,_free,_get_str_from_wasm,_set_str_from_js]" \ --no-entry \ -o \ ./index.wasm clean: rm -rfv *.wasm
index.html 因为
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Shared</title> </head> <script type="text/javascript"> (async function () { function AsciiToString(ptr, heapu8) { let str = ''; while (1) { let ch = heapu8[ptr++]; if (!ch) return str; str += String.fromCharCode(ch); } } const resp = await fetch(`./index.wasm?t=${Date.now()}`); const bytes = await resp.arrayBuffer(); const { instance } = await WebAssembly.instantiate(bytes, { env: {}, }); const str = "Hello, From JS"; const str_ptr = instance.exports.malloc(str.length); const HEAP8 = new Int8Array(instance.exports.memory.buffer); // 1 byte 1 byte 的形式去内存中设置值,直接修改 wasm 内存数据 str.split('').forEach((char, index) => { HEAP8[(str_ptr + index) >> 0] = char.charCodeAt(0); }); // 传递指针 instance.exports.set_str_from_js(str_ptr); // 获取值 const str_ptr_from_wasm = instance.exports.get_str_from_js(); const str_from_wasm = AsciiToString(str_ptr_from_wasm, HEAP8); console.log(str_from_wasm); // "Hello, From JS" })().catch(err => console.error(err)); </script> </body> </html>
可以看出,string 是不能直接通过 API 形式传递,需要开辟内存空间,往对应的内存空间写数据,再把 pointer 传入到 wasm 方法去。
其他类型数据
其他高级类型数据和对应的存储结构有关,可以通过高阶的 wrap 形式来做传递,本质上和 String 的传递类似。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律