我目前正在尝试开发一个web应用的一部分使用Rust编译成wasm部分(也有类似的框架如yew等),但是我发现使用webassembly可能会有更多的消耗,比如我必须做一个点击按钮调用一个JS函数。 JS函数进行一些计算(很简单的计算)并将结果呈现给dom
只使用js的解决方案:
- JS调用另一个JS函数
- 另一个 JS 函数执行一些计算并通过文档的一些 API 直接呈现结果。
使用Rust + Webassembly的方案:
- JS调用一个wasm函数
- Wasm 执行一些计算。计算完成后,将结果编码成TypedArray,调用JS函数渲染dom。
- JS解码TypeArray中对应的内容,然后将dom渲染到屏幕上。
这里不考虑使用React或者Vue,仅仅使用WebAssembly可能会降低性能,主要体现在:
- 更多函数调用
- 添加了编码/解码过程和可能的内存副本。
Webassembly 的优势可能是计算速度更快,但是这个优势很可能不会因为上面提到的增加的开销而节省整体时间,而且在 DOM 操作上明显慢。
不过我还是做了一个DOM操作的对比测试:
JS 创建 10,000 个 p-tags 大约需要 120ms:
function web_bench() {
let container = document.getElementById("container");
let begin = Date.now();
for(let i = 0; i < 10000; i += 1) {
let str = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456abcd123456789012345678901234567890123456789012345678901234567890" +
"1234567890123456789012345678901234567890123456789012345678哈哈1234567890123456789012345678901234567890" +
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
"1234567890123456789012345678901234567890123456789哈哈2345678901234567890123456789012345678901234567890" +
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890123嘻嘻67890123456789012345678901234567890" +
"12345678901234567890123456789012345678901234哈哈哈012345678901234567890123456789012345678901234567890";
let p = document.createElement("p");
p.innerHTML = str;
container.appendChild(p);
}
let time = Date.now() - begin;
console.log('cost time:', time);
}
如果我使用 rust:花费 180 毫秒
#[wasm_bindgen]
pub fn bench() {
let document = web_sys::window().unwrap().document().unwrap();
for i in 0..10000 {
let str = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456abcd1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678哈哈123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789哈哈234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678902345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123嘻嘻6789012345678901234567890123456789012345678901234567890123456789012345678901234哈哈哈012345678901234567890123456789012345678901234567890";
let p = document
.create_element("p")
.unwrap();
p.set_inner_html(str);
document
.get_element_by_id("container")
.unwrap()
.append_child(&p);
}
}
这是不是说rust+wasm不适合做与dom操作交互频繁的web开发,只适合做计算模块。目前的 Rust web 框架是如何看待这个问题的?我的分析正确吗?
谢谢你的意见~
最佳答案
有几件事会增加 JS <=> WebAssembly 调用的开销,并影响性能:
- WebAssembly 和 JavaScript 之间的通信涉及相当多的开销,涉及通过 C++ 代码称为 trampolining 的过程。
- 为了交换数据(简单数字除外),需要通过线性存储器对值进行编码/解码。
这两者都会在每个函数调用的基础上产生可衡量的开销。
不过,情况正在好转......
- 浏览器 vendor 是 looking to remove the trampolining .
- 通过 interface types提议,编码/解码开销将显着减少。
WebAssembly 是一项非常新的技术,需要时间来优化和解决性能问题。
Does this mean that rust+wasm is not suitable for web development that interacts frequently with dom operations
目前,可能是。将来,这可能是可行的
Is my analysis correct?
您目前的观察,目前它有点慢是正确的。
关于javascript - 使用rust+webassembly进行web开发,如何解决wasm与js交互的额外开销,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59015066/