2023年,Rust能干掉JavaScript吗?

作者 | Josh Mo
译者 | 核子可乐
策划 | 李冬梅
如果大家已经拥有一定的 Rust Web 开发经验,应该听说过在前端 Web 开发上用 Rust(通过 WASM)还是用 JAVA 这个充满争议性的话题 。不少人旗帜鲜明表示反对,认为 Rust“不适合生产”,而且速率“比 Java 还慢” 。
这种说法也有道理:从历史上看,因为 WASM 无法访问 DOM,所以从 Java 调用 WASM 确实会产生额外开销 。但目前这方面的影响已经很小,基准数据显示,像 Leptos 和 Dioxus 这样的 Rust WASM 框架(底层使用 Sledgehammer,属于速度前三甲级别的 Java 框架)在性能上已经优于 React 和 Vue 等大部分 JS 框架 。感兴趣的朋友可以参考原始基准测试 。

2023年,Rust能干掉JavaScript吗?

文章插图
【2023年,Rust能干掉JavaScript吗?】如图片所见,各框架按性能排序分别为原始 Java、Sledgehammer(Dioxus 的底层引擎)、wasm-bindgen(允许 WASM 模块和 Java 实现互操作的库)、Solid.js ,Vue 和 RxJS,之后是 Leptos、Dioxus、LitJS,接下来是 Sycamore……排在最末的才是 Vue 和 React(还有 Yew) 。很明显,其中一些 Rust 前端框架甚至比最流行的 Java 框架性能还好 。千万别抬杠说也可以不用框架,直接编写纯 Java 代码——确实可以,但这明显偏离本文讨论的主题了 。
TechEmpower 发布的后端性能基准测试:
在前 10 大后端框架中,有 5 个是用 Rust 编写的 。很明显,Rust 在后端框架领域占据着突出的优势,甚至能与 C++ 正面较量 。有人可能会说 Rust 用作后端服务有点太过了——但它确实能带来更高性能,占用的内存更小、服务的运行稳定性更好、引发崩溃的可能性也更低 。这些都是不容低估的重要因素,毕竟从企业的角度来看,尽可能节约成本永远都是高优先级事项 。
但也必须承认,在选择新框架时,速度和常规性能往往并不足以构成综合决策的充分因素 。开发者体验如何、错误处理功能是否强大、怎样解决 SSR 问题等也都非常重要 。要想做出明智的最终选择,必须先为这些问题找到合理答案 。幸运的是,Rust 同样是有备而来 。
开发者体验
不管大家主观判断如何,在 Web 开发方面,Rust 有着相对宽松的使用要求 。其中很多代码的样式上跟 React 等 Web 框架中的 Java 组件非常相似——比如 Leptos(一款 Rust Web 框架)中的组件代码:
use leptos::*;#[component]pub fn SimpleCounter(cx: Scope, initial_value: i32) -> impl IntoView{// create a reactive signal with the initial valuelet(value, set_value) = create_signal(cx, initial_value);
// create event handlers for our buttons// note that `value` and `set_value` are `Copy`, so it's super easy to move them into closures// (for reference: closures are like anonymous/arrow functions in Java)letclear = move |_| set_value(0);letdecrement = move |_| set_value.update(|value| *value -= 1);letincrement = move |_| set_value.update(|value| *value += 1);
// create user interfaces with the declarative `view!` macroview! {cx,<div><button on:click=clear>"Clear"</button><button on:click=decrement>"-1"</button><span>"Value: "{value} "!"</span><button on:click=increment>"+1"</button></div>}}
// Easy to use with Trunk (trunkrs.dev) or with a simple wasm-bindgen setuppub fn main() {mount_to_body(|cx| view! { cx, <SimpleCounterinitial_value=https://www.isolves.com/it/cxkf/yy/Rust/2023-05-09/3/> })}
可以看到,这些代码其实跟 JSX 区别不大,最大的不同就是该组件不返回任何内容,而是用 Rust 宏来渲染 html 。其 main 函数类似于 React、Vue 乃至其他 JS 框架当中作用于 root 文件的 index.js 脚本 。再来看另一个来自 Dioxus 的例子:
// An example of a navbarfn navbar(cx: Scope) -> Element {cx.render(rsx! {ul {// NEWLink { to: "/", "Home"}br {}Link { to: "/blog", "Blog"}}})}// An example of using URL parametersfn get_blog_post(id: &str) -> String{match id {"foo"=> "Welcome to the foo blog post!".to_string(),"bar"=> "This is the bar blog post!".to_string(),id=>format!("Blog post '{id}' does not exist!")}
可以看到,RSX(相当于 Dioxus 中的 React JSX)的编写非常简单,甚至可能比使用 Leptos 还简单一些 。而且很明显,React 的组件设计理念已经超越了特定编程语言,在 Rust 这边也已经有所体现 。大家甚至可以把这些函数跟单元结构体(unit structs)结合起来,为各种函数提供命名空间,这样就能实现对 API 调用之类的捆绑了,例如:


推荐阅读