跳到主要内容
Deno 2 终于来了 🎉️
了解更多

宣布 Rust 的稳定版 V8 绑定

Deno 是一个用 Rust 编写的现代、零配置 JavaScript 运行时。它的核心是 Rusty V8,这是一个为 V8 的 C++ API 提供高质量、零开销 Rust 绑定的库。在过去的五年里,Rusty V8 经历了近 150 次发布,在 crates.io 上获得了超过 310 万次的下载。今天,我们很高兴地宣布一个重要的里程碑:Rusty V8 现在是稳定的,可以投入生产了

虽然我们很乐意用“1.0”版本来纪念这一刻,但 Rusty V8 完全跳过了 1.0 版本。相反,我们与 Chrome 的版本控制方案保持一致,以与 V8 同步。Rusty V8 的第一个稳定版本将是 129.0.0 版本,与 Chrome 129 一致。此版本保证了 API 的稳定性,让我们告别了多年的 0.x 版本,并巩固了 Rusty V8 作为开发人员在 V8 之上构建项目的可靠工具的地位。

Rusty V8 的特别之处是什么?

Rusty V8 为 Rust 开发人员提供了对 V8 的 C++ API 的直接、零开销访问。它以其完整性和与高性能环境的无缝集成而脱颖而出。一个关键特性是 Rusty V8 自动将 V8 的复杂构建系统集成到 Cargo 中,使开发人员能够轻松地将 V8 嵌入 Rust 项目中,无需手动设置。使用 Rusty V8,您可以

  • 构建自定义 JavaScript 运行时: Rusty V8 非常适合创建您自己的 JavaScript 运行时,无论是用于嵌入式设备、无服务器环境还是插件系统。
  • 运行 WebAssembly 模块: Rusty V8 无缝地执行 WebAssembly (Wasm) 模块,使您能够在 JavaScript 旁边运行高性能代码。
  • 利用 V8 Inspector: 使用 V8 Inspector 将断点和分析等调试功能添加到您的 JavaScript 运行时。
  • 使用 V8 Fast API: Rusty V8 使您能够以最小的开销从 JavaScript 调用 Rust 函数,非常适合高性能应用程序。
  • 自动内存管理: V8 的 cppgc 垃圾收集器有助于有效地管理内存,减少了在复杂应用程序中手动处理内存的需求。

起源故事

通往 Rusty V8 的旅程始于 2015 年,当时我正在尝试使用一个名为 v8worker 的库在 Go 中构建 JavaScript 运行时。最终,v8worker 被用于第一个 Deno 演示。但是,随着 Deno 的发展,很明显 Go 不适合该项目,因为担心 Go 自己的 GC 会与 V8 的 GC 产生不良冲突。

在 2019 年底,Deno 联合创始人 Bert Belder 带领团队努力创建了对 V8 的直接 Rust 绑定。挑战在于将 V8 复杂的 C++ API 绑定到 Rust,而不损害性能或安全性。经过不懈努力,Rusty V8 诞生了——一个针对 V8 的零开销 Rust 绑定,它提供了对 V8 的完全控制,同时通过 Rust 的所有权模型确保内存安全性。

使用 Rusty V8

以下是如何使用 Rusty V8 将 JavaScript 嵌入 Rust 程序的简单示例

fn main() {
  // Initialize V8.
  let platform = v8::new_default_platform(0, false).make_shared();
  v8::V8::initialize_platform(platform);
  v8::V8::initialize();

  // Create a new Isolate and make it the current one.
  let isolate = &mut v8::Isolate::new(v8::CreateParams::default());

  // Create a stack-allocated handle scope.
  let handle_scope = &mut v8::HandleScope::new(isolate);

  // Create a new context.
  let context = v8::Context::new(handle_scope, Default::default());

  // Enter the context for compiling and running the hello world script.
  let scope = &mut v8::ContextScope::new(handle_scope, context);

  // Create a string containing the JavaScript source code.
  let code = v8::String::new(scope, "'Hello' + ' World!'").unwrap();

  // Compile the source code.
  let script = v8::Script::compile(scope, code, None).unwrap();

  // Run the script to get the result.
  let result = script.run(scope).unwrap();

  // Convert the result to a string and print it.
  let result = result.to_string(scope).unwrap();
  println!("{}", result.to_rust_string_lossy(scope));
}

Rusty V8 的内存安全特性是其相对于 C++ API 的核心优势。例如,在 Rust 中,Local<T> 等句柄与特定作用域绑定,并在编译时强制执行。这可以防止由于使用或返回无效句柄而导致的错误——这必须由 C++ 开发人员手动管理。在 Rust 中,如果您尝试在作用域之外使用 Local<T>,编译器会捕获该错误。

以下是如何阻止 Rust 使用无效句柄的快速示例

let isolate = &mut v8::Isolate::new(Default::default());
{
  let scope1 = &mut v8::HandleScope::new(isolate);
  let local = v8::Integer::new(scope1, 123);

  // Attempting to use 'local' outside the scope will fail at compile time
  let invalid_local = {
    let scope2 = &mut v8::HandleScope::new(scope1);
    v8::Integer::new(scope2, 456) // Safe to use in this scope
  };

  // Rust will not allow 'invalid_local' to be accessed here.
}

版本控制

为了与 V8 保持一致,Rusty V8 将遵循 Chrome 的版本控制方案。第一个稳定版本是 129.0.0 版本,对应于 Chrome 129。虽然 V8 不遵循语义版本控制 (semver),即使在次要版本中也可能引入重大更改,但 Rusty V8 将遵循 semver,以确保 Rust 开发人员的兼容性和稳定性。

每 4 周,Rusty V8 将升级其 V8 依赖项并提升其主版本。这意味着对 Rusty V8 API 的重大更改只会发生在 V8 升级时,并且该版本始终反映底层的 V8 版本。

准备投入生产

Rusty V8 现在是一个稳定的、可以投入生产的库,用于在 Rust 中构建高性能 JavaScript 和 WebAssembly 运行时。无论您是创建自定义 JavaScript 运行时、将 JS 嵌入 Rust 支持的应用程序中,还是探索服务器端 JavaScript 应用程序,Rusty V8 都提供了 V8 的灵活性以及 Rust 的安全性和性能保证。

通过在 docs.rs/v8 上探索完整的文档,可以更深入地了解。