使用rust + webassembly进行Web开发,如何解决wasm和js交互的额外成本

聂小涛*_*聂小涛 3 javascript rust webassembly

我目前正在尝试使用Rust编译为wasm部分(有类似的框架,例如yew等)来开发Web应用程序的一部分,但是我发现使用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-tag,耗时约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);
}
Run Code Online (Sandbox Code Playgroud)

如果我使用生锈:花费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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是否意味着rust + wasm不适合与dom操作频繁交互的Web开发,而仅适合于计算模块。当前的Rust Web框架如何看待这个问题?我的分析正确吗?

谢谢您的意见〜

Col*_*inE 5

有几件事会增加JS <=> WebAssembly调用的开销并影响性能:

  1. WebAssembly与JavaScript之间的通信涉及很多开销,其中涉及一个通过C ++代码进行蹦床的过程。
  2. 为了交换数据​​(简单数字除外),需要通过线性存储器对值进行编码/解码。

这两种功能均对每个函数调用造成了可测量的开销。

但是,情况正在改善...

  1. 浏览器供应商正在寻求消除蹦床
  2. 通过接口类型建议,编码/解码开销将大大减少。

WebAssembly是一项非常新的技术,它需要时间来优化和解决性能问题。

这是否意味着rust + wasm不适合与dom操作频繁交互的Web开发

目前,可能是。将来,这可能是可行的

我的分析正确吗?

您当前的观察结果表明,此刻有点慢是正确的。