参考类型支持

WebAssembly 最近获得了对一种名为 externref 的新值类型的支持。这个 WebAssembly 的特性是在 WebAssembly 参考类型仓库 中提出的,希望能实现主机 (JS) 和 Wasm 模块之间更高效的通信。此特性消除了 wasm-bindgen 生成的大部分 JS 胶水的需要,因为它可以使用 JS 值原生调用 API。

例如,这个 Rust 函数


# #![allow(unused_variables)]
#fn main() {
#[wasm_bindgen]
pub fn takes_js_value(a: &JsValue) {
    // ...
}
#}

在没有参考类型支持的情况下生成此 JS 胶水

const heap = new Array(32).fill(undefined);

heap.push(undefined, null, true, false);

let stack_pointer = 32;

function addBorrowedObject(obj) {
    if (stack_pointer == 1) throw new Error('out of js stack');
    heap[--stack_pointer] = obj;
    return stack_pointer;
}

export function takes_js_value(a) {
    try {
        wasm.takes_js_value(addBorrowedObject(a));
    } finally {
        heap[stack_pointer++] = undefined;
    }
}

我们可以在这里看到,在底层,JS 如何管理一个传递给 Wasm 二进制的 JS 值表,因此 Wasm 实际上只在索引中工作。但是,如果我们使用 -Ctarget-feature=+reference-types (从 Rust v1.82 开始默认)进行编译,则生成的 JS 如下所示

export function takes_js_value(a) {
    wasm.takes_js_value(a);
}

就是这样!WebAssembly 二进制文件直接获取 JS 值并在内部进行管理。

目前,此功能在 Firefox 79+ 和 Chrome 中受支持。在其他浏览器中的支持可能很快就会到来!在 Node.js 中,此功能位于 --experimental-wasm-anyref 标志之后,尽管截至 14.6.0,该支持目前与上游规范不一致。