如何从WebAssembly函数返回JavaScript字符串?
以下模块可以用C(++)编写吗?
export function foo() {
return 'Hello World!';
}
另外:我可以将它传递给JS引擎进行垃圾回收吗?
答案 0 :(得分:41)
WebAssembly本身不支持字符串类型,而是支持i32
/ i64
/ f32
/ f64
value types以及{{1 } / i8
用于存储。
您可以使用以下方式与WebAssembly实例进行交互:
exports
,您从JavaScript调用WebAssembly,而WebAssembly返回单个值类型。imports
其中WebAssembly调用JavaScript,使用尽可能多的值类型(注意:必须在模块编译时知道计数,这不是数组且不是可变参数)。Memory.buffer
,i16
,可以使用ArrayBuffer
(等)进行索引。这取决于你想做什么,但似乎直接访问缓冲区是最简单的:
Uint8Array
如果你的模块有start
function,那么它会在实例化时执行。否则你可能会有一个你打电话的导出,例如const bin = ...; // WebAssembly binary, I assume below that it imports a memory from module "imports", field "memory".
const module = new WebAssembly.Module(bin);
const memory = new WebAssembly.Memory({ initial: 2 }); // Size is in pages.
const instance = new WebAssembly.Instance(module, { imports: { memory: memory } });
const arrayBuffer = memory.buffer;
const buffer = new Uint8Array(arrayBuffer);
。
一旦完成,你需要在内存中获得字符串大小+索引,你也可以通过导出公开:
instance.exports.doIt()
然后你将它从缓冲区中读出来:
const size = instance.exports.myStringSize();
const index = instance.exports.myStringIndex();
请注意,我正在从缓冲区读取8位值,因此我假设字符串是ASCII。这就是let s = "";
for (let i = index; i < index + size; ++i)
s += String.fromCharCode(buffer[i]);
给你的内容(内存中的索引将是std::string
返回的内容),但是为了暴露其他东西,例如UTF-8,你需要使用支持UTF-8的C ++库,以及然后自己从JavaScript读取UTF-8,获取代码点,并使用.c_str()
。
你也可以依赖于以null结尾的字符串,我在这里没有这样做。
通过在String.fromCodePoint
的{{1}} WebAssembly.Memory
buffer
中创建TextDecoder
API,您也可以在浏览器中更广泛地使用ArrayBufferView
})。
相反,如果您正在执行从WebAssembly到JavaScript的操作,那么您可以如上所述公开ArrayBuffer
,然后从WebAssembly声明一个调用JavaScript的大小+位置的导入。您可以将模块实例化为:
Memory
这有一点需要注意,如果你增加内存(使用const memory = new WebAssembly.Memory({ initial: 2 });
const arrayBuffer = memory.buffer;
const buffer = new Uint8Array(arrayBuffer);
const instance = new WebAssembly.Instance(module, {
imports: {
memory: memory,
logString: (size, index) => {
let s = "";
for (let i = index; i < index + size; ++i)
s += String.fromCharCode(buffer[i]);
console.log(s);
}
});
的JavaScript或使用Memory.prototype.grow
操作码),那么grow_memory
会被中断,你需要创建它重新
关于垃圾收集:ArrayBuffer
/ WebAssembly.Module
/ WebAssembly.Instance
都是JavaScript引擎收集的垃圾,但这是一个非常大的问题。您可能想要GC字符串,而这对于WebAssembly.Memory
内的对象来说是不可能的。我们已经讨论了adding GC support in the future。
答案 1 :(得分:3)
给出:
mem
,WebAssembly.Memory
对象(来自模块导出)p
,字符串的第一个字符的地址len
,字符串的长度(以字节为单位),您可以使用以下命令读取字符串:
let str = (new TextDecoder()).decode(new Uint8Array(mem.buffer, p, len));
这假定字符串是UTF-8编码的。
答案 2 :(得分:0)
我发现了一种破解方法,就像我们在混合应用程序中所做的一样,而且非常容易。
只需注入window.alert
函数,然后放回原处:
let originAlert = window.alert;
window.alert = function(message) {
renderChart(JSON.parse(message))
};
get_data_from_alert();
window.alert = originAlert;
和原生方面,只是:
// Import the `window.alert` function from the Web.
#[wasm_bindgen]
extern "C" {
fn alert(s: &str);
}
...
pub fn get_data_from_alert() {
alert(CHART_DATA);
}
您可以在示例中看到我的GitHub:https://github.com/phodal/rust-wasm-d3js-sample