AssemblyScript字符串函数报错,i32函数正常,如何修复?
问题描述
编写了一个AssemblyScript的parse函数,用于接收并返回字符串类型值,对应的NodeJS导入运行代码执行时出现错误:TypeError: WebAssembly.instantiate(): Imports argument must be present and must be an object。但当函数使用i32类型参数和返回值时,代码可正常运行并输出结果。需要修复该问题以支持字符串处理。
字符串版本代码(报错)
AssemblyScript代码
export function parse(x: string): string { return x; }
NodeJS代码
import { readFileSync } from 'fs'; export default async function compile(raw) { return WebAssembly.instantiate( readFileSync('./src/.assembly/engine.wasm') // 编译后的AssemblyScript WASM文件 ).then(mod => { const { parse } = mod.instance.exports; return parse(raw); }); } compile('test').then(res => { console.log(res); });
错误信息
node:internal/process/promises:288 triggerUncaughtException(err, true /* fromPromise */); ^ [TypeError: WebAssembly.instantiate(): Imports argument must be present and must be an object] Node.js v18.15.0 error Command failed with exit code 1.
i32版本代码(正常运行)
AssemblyScript代码
export function parse(x: i32): i32 { return x; }
NodeJS代码
import { readFileSync } from 'fs'; export default async function compile(raw) { return WebAssembly.instantiate( readFileSync('./src/.assembly/engine.wasm') // 编译后的AssemblyScript WASM文件 ).then(mod => { const { parse } = mod.instance.exports; return parse(raw); }); } compile(44).then(res => { console.log(res); });
运行结果
44
问题原因
WebAssembly本身没有原生字符串类型,AssemblyScript的字符串是通过内存中存储UTF-8编码数据+长度的方式实现的,这依赖AssemblyScript的运行时来处理内存分配、字符串编码转换等逻辑。当处理字符串时,WASM模块需要宿主环境(NodeJS)提供对应的导入对象来支持这些运行时功能;而i32是WASM原生支持的数值类型,无需额外依赖,因此可以直接运行。
修复方案
推荐使用AssemblyScript官方提供的@assemblyscript/loader库来简化WASM模块的加载和字符串类型的转换,该库会自动处理运行时依赖和类型转换逻辑。
步骤1:安装依赖
npm install @assemblyscript/loader
步骤2:修改NodeJS代码
import { readFileSync } from 'fs'; import loader from '@assemblyscript/loader'; export default async function compile(raw) { // 使用loader加载WASM模块,自动处理运行时导入 const wasmModule = await loader.instantiate( readFileSync('./src/.assembly/engine.wasm'), {} // 如需自定义导入可在此添加,默认空对象即可满足基础字符串处理需求 ); // 从WASM导出中获取必要的方法:业务函数parse,以及字符串转换工具函数 const { parse, __newString, __getString } = wasmModule.exports; // 1. 将JS字符串转换为WASM可识别的字符串引用(分配内存并写入UTF-8数据) const wasmStringRef = __newString(raw); // 2. 调用parse函数,返回WASM字符串引用 const resultRef = parse(wasmStringRef); // 3. 将WASM字符串引用转换回JS字符串(从内存读取UTF-8数据并解码) const result = __getString(resultRef); return result; } compile('test').then(res => { console.log(res); // 输出:test });
注意事项
- 编译AssemblyScript时不要添加
--noRuntime参数,默认编译会包含必要的运行时代码,确保WASM模块能正常处理字符串等复杂类型。 - 如果需要手动实现导入对象(不使用loader),需要自行提供内存管理、字符串处理相关的导入函数,这会非常繁琐,因此推荐使用官方loader。
内容的提问来源于stack exchange,提问作者user21392777
相关产品推荐
相关产品推荐

