You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何将DOM对象作为externref传递给Wasm比通过JS值表传递速度更慢

基准测试背景

我制作了一个基准测试,用于衡量将DOM对象作为externref传递给Wasm函数时调用DOM API的速度。以下是被测试的函数(使用Rust编写,由rustc 1.55.0编译):

#[wasm_bindgen]
pub fn append_and_remove(elem: web_sys::Element) {
    let doc = web_sys::window().unwrap().document().unwrap();
    let child = &doc.create_element("br").unwrap();
    elem.append_with_node_1(child).unwrap();
    let _ = elem.remove_child(child).unwrap();
}

我对比了两个Wasm模块(及其JS包装层)和等效的JavaScript代码:其中“启用引用类型”版本使用wasm-bindgen --reference-types预处理,另一“未启用引用类型”版本仅使用wasm-bindgen预处理。

一百万次调用测试结果(Windows 10 64位环境)

浏览器分组耗时(毫秒)
Firefox 94.0.1未启用引用类型2167
启用引用类型2687
纯JavaScript实现637
Chrome 95.0.4638.69未启用引用类型3432
启用引用类型4129
纯JavaScript实现1039
Edge 95.0.1020.44未启用引用类型3416
启用引用类型3858
纯JavaScript实现1187

问题解答

三款浏览器中未启用引用类型的版本性能反而更高,核心原因有三个:

  • 引用类型的跨边界校验开销未被充分优化
    未启用引用类型时,wasm-bindgen 会把所有DOM对象存在JS侧的全局索引表中,传给Wasm的只是整数索引,Wasm侧完全按普通数值处理,跨边界时不需要额外类型校验,这条路径已经被浏览器引擎优化了多年,性能非常成熟。
    启用引用类型后,Wasm栈直接存储JS对象引用,每次跨Wasm/JS边界调用时,引擎都需要额外做引用合法性校验:包括空值判断、类型约束校验、GC标记同步等,你测试所用的2021年发布的9x版本Chrome/Firefox/Edge对这部分逻辑的JIT优化还不到位,直接带来了显著的额外开销。
  • wasm-bindgen 引用类型的代码生成未做极致优化
    你看到的只是外层包装代码量减少,但底层的参数处理逻辑反而多了额外开销:未启用引用类型时整数参数可以直接透传,启用引用类型后,每次传递对象进Wasm、或者从Wasm返回对象时,都要做额外的引用持有/释放标记,避免对象被GC误回收,这部分逻辑也拉高了耗时。
  • 测试场景放大了边界开销的影响
    你的测试函数本身逻辑极轻,绝大多数耗时都集中在Wasm和JS的跨边界调用上,所以边界调用的额外开销占比被完全放大。如果是计算密集型、跨边界调用频次低的场景,引用类型省去的索引查表开销反而会体现出优势,只是在你这个高频跨边界调用的场景下,当前的校验开销盖过了它的收益。

目前浏览器对Wasm引用类型的优化还在持续迭代,后续随着引擎JIT对引用类型边界调用的优化到位,这个性能差距会逐步缩小甚至反转。


内容的提问来源于stack exchange,提问作者YAMAMOTO Yuji

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 23:54:03