(最初发布于 deno.com/blog)
Deno 是一个现代的、零配置的 JavaScript 运行时,用 Rust 编写。其核心是 Rusty V8,这是一个提供高质量、零成本的 Rust 绑定到 V8 的 C++ API 的库。在过去五年,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
垃圾收集器有助于高效地管理内存,减少复杂应用程序中的手动内存管理需求。
这段旅程始于2015年,当时我尝试用Go语言和一个名为v8worker的库构建一个JavaScript运行时。最终,它被用于第一个Deno演示。然而,随着Deno的发展,很明显Go并不适合该项目。因为担心Go自己的垃圾回收机制与V8存在冲突。
在2019年末,Deno 的联合创始人 Bert Belder 主导了创建直接将 Rust 与 V8 相绑定的努力。挑战在于将 V8 复杂的 C++ API 绑定到 Rust,同时在不牺牲性能和安全性的前提下完成这一任务。经过不懈努力,于是诞生了 Rusty V8,一个零开销的 Rust 绑定,它提供了对 V8 的完全控制权,并通过 Rust 的所有权模型确保内存安全。
使用 Rusty V8(锈V8)这里有一个简单的例子,说明如何使用 Rusty V8 在 Rust 程序中插入 JavaScript。
fn main() {
// 初始化 V8。
let platform = v8::new_default_platform(0, false).make_shared();
v8::V8::initialize_platform(platform);
v8::V8::initialize();
// 创建一个新的 Isolate 并将其设置为当前 Isolate。
let isolate = &mut v8::Isolate::new(v8::CreateParams::default());
// 创建一个栈分配的句柄作用域。
let handle_scope = &mut v8::HandleScope::new(isolate);
// 创建一个新的执行环境。
let context = v8::Context::new(handle_scope, Default::default());
// 进入上下文以编译和运行 "Hello World" 脚本内容。
let scope = &mut v8::ContextScope::new(handle_scope, context);
// 创建一个包含 JavaScript 源代码的字符串。
let code = v8::String::new(scope, "'Hello' + ' World!'").unwrap();
// 编译源代码。
let script = v8::Script::compile(scope, code, None).unwrap();
// 运行脚本以获取结果。
let result = script.run(scope).unwrap();
// 将结果转换为字符串并输出。
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);
// 尝试在该作用域之外使用 'local' 将会在编译时失败
let invalid_local = {
let scope2 = &mut v8::HandleScope::new(scope1);
v8::Integer::new(scope2, 456) // 在此作用域内使用是安全的,但一旦离开该作用域,就无法访问了
};
// Rust 不允许在这里访问 'invalid_local'。
}
版本控制
为了与 V8 保持一致,Rusty V8 将采用 Chrome 的版本方案。首个稳定版本为 129.0.0 版,与 Chrome 129 对应。虽然 V8 并不遵循语义化版本(semver),在次要版本中也可能引入破坏性更改,Rusty V8 将遵循 semver,以确保对 Rust 开发者的兼容性和稳定性。
每隔4周,Rusty V8会升级其V8依赖并提升其主版本。这意味着破坏性更改只会发生在V8升级时,而Rusty V8的API也随之更新,且版本号将始终与底层V8版本保持一致。
准备好了,可以开始生产了Rusty V8 现已是一个稳定且可以用于生产的库,用于在 Rust 中构建高性能的 JavaScript 和 WebAssembly 运行时。无论你是在创建自定义的 JavaScript 运行时、在由 Rust 支持的应用中嵌入 JS,还是探索服务器端的 JavaScript 应用,Rusty V8 都提供了 V8 的灵活性,同时保证了 Rust 的安全性和性能。
通过访问docs.rs/v8探索完整文档,了解更多。
共同學習,寫下你的評論
評論加載中...
作者其他優質文章