为什么JS/React比WebAssembly/Rust更快?对象创建场景测试疑问
核心原因
你遇到的性能差异几乎全部来自Wasm与JavaScript的跨边界序列化开销,你的Rust实现存在明显的不必要性能损耗点,和Rust本身的执行效率无关:
- 你使用了
JsValue::from_serde做类型转换:这个方法的底层逻辑是先把Rust侧的Vec/结构体序列化为JSON字符串,再将JSON字符串反序列化为JS原生对象,两次额外的全局转换开销远高于直接在JS中生成对象的成本。 - 第二种HashMap实现的额外开销更高:HashMap本身的插入、哈希计算就有固定开销,序列化阶段还要处理哈希表的KV结构转换,速度只会更慢。
为什么JS实现速度更快
你测试的逻辑本身就是JS引擎的高度优化场景:V8对原生对象创建、数组push操作做了十几年的极致JIT优化,全程在JS runtime内完成,没有任何跨模块转换成本。
而你的Rust实现中,实际数组创建、元素插入的开销只占总耗时的很小一部分,90%以上的时间都花在了serde序列化+JS侧反序列化的步骤上,自然跑不过原生JS实现。
优化方案
如果要缩小性能差距甚至反超,需要规避跨边界的全局序列化开销:
- 放弃serde全量转换,直接用wasm_bindgen提供的
JsArray、JsObject接口手动在Wasm侧构建JS原生对象,直接返回构造好的JsArray,省掉JSON序列化/反序列化步骤,参考实现:
use wasm_bindgen::prelude::*; use js_sys::{JsArray, JsObject, Reflect}; #[wasm_bindgen] pub fn create_rust_objects(amount: usize) -> JsArray { let arr = JsArray::new_with_length(amount as u32); for i in 0..amount { let obj = JsObject::new(); Reflect::set(&obj, &"index".into(), &i.into()).unwrap(); arr.set(i as u32, obj); } arr }
- 如果数据结构规整,优先用TypedArray传递批量数据:比如所有元素只有index数值,可以直接返回
Uint32Array,Wasm内存可以直接和JS共享,几乎没有转换开销。 - 编译时开启release优化,配置
opt-level=3、lto=true,进一步压缩Rust侧的执行开销。
内容的提问来源于stack exchange,提问作者Stephan Bakkelund Valois
相关产品推荐
相关产品推荐

