首页
/ deno_runtime 运行时库剖析:MainWorker、bootstrap 流程与 WebWorker 架构(Deno 源码实战)

deno_runtime 运行时库剖析:MainWorker、bootstrap 流程与 WebWorker 架构(Deno 源码实战)

2026-09-04 20:07:45作者:彭桢灵Jeremy

本文基于 Deno 仓库中的 runtime/README.md 展开,系统讲解 deno_runtime crate 的定位与 API 设计:如何以 MainWorker 封装 deno_core::JsRuntime 并注入 Deno 命名空间的 ops、如何完成 bootstrap 初始化、如何通过 WorkerOptions/BootstrapOptions 定制模块加载、错误格式化、V8 inspector、User-Agent、CA 证书与随机数种子等运行时属性,以及 WebWorker 如何以“每 worker 一个专用 OS 线程”的模型实现 Web Worker API。读完后你可以理解 Deno CLI 的运行时底座是如何搭建的,并具备在自定义宿主中嵌入 deno_runtime 的工程思路。

deno_runtime 是什么:Deno CLI 的“瘦身版”

README 对 crate 的定义非常明确:它是 Deno CLI 的精简版本,移除了 TypeScript 集成以及 lint、doc 等工具链,本质上只保留JavaScript 执行能力加上 Deno 的操作系统绑定(ops)。这个 crate 发布在 crates.io 上,包名为 deno_runtime,当前仓库中版本为 0.266.0,描述为 "Provides the deno runtime library"(见 runtime/Cargo.toml)。

README 同时给出了一段重要的稳定性声明:该 crate 由原先位于 deno crate 中、久经考验的模块构建而成,但其 API 处于快速变化阶段,随时可能发生破坏性变更。因此引用它的下游项目需要做好跟随升级的准备。

runtime/Cargo.toml 的 features 定义可以看出该 crate 的几个编译开关,它们对应不同的集成场景:

  • docsrs:一个"假 feature",仅用于在 docs.rs 上正常生成文档;
  • exclude_runtime_main_js:从导出的扩展中排除 js/99_main.js,适合宿主希望自行接管主模块引导逻辑的场景;
  • snapshot / transpile:启用 V8 快照能力(snapshot 依赖 transpile,后者引入 deno_ast);
  • hmr:开发特性,禁用快照的创建与加载,改为在运行时从磁盘读取各扩展的 lazy_loaded_* 源文件。

它聚合了哪些能力

deno_runtime 自身并不从零实现 Web API,而是把 Deno 的各个能力 crate 重新导出并组装。从 runtime/lib.rs 可以看到它 pub use 了二十多个功能模块:

pub use deno_cache;
pub use deno_core;
pub use deno_crypto;
pub use deno_fetch;
pub use deno_ffi;
pub use deno_fs;
pub use deno_http;
pub use deno_kv;
pub use deno_napi;
pub use deno_net;
pub use deno_node;
pub use deno_os;
pub use deno_permissions;
pub use deno_process;
pub use deno_web;
pub use deno_webgpu;
pub use deno_websocket;
// ...

并对外暴露了自身的关键模块:code_cache(V8 代码缓存)、coverage(覆盖率)、cpu_profiler(CPU 剖析)、fmt_errors(错误格式化)、js(内置 JS 源)、ops(宿主 ops)、permissions(权限系统)、snapshot(快照,feature 开关控制)、web_workerworker 等。此外还重导出 deno_features 中的 FeatureCheckerUNSTABLE_FEATURES,用于 --unstable-* 特性门禁。换句话说,README 所说的“JavaScript 执行 + 操作系统绑定”在这套 re-export 与扩展注册中得到了具体体现。

主 API:MainWorker

README 指出该 crate 的主 API 是 MainWorker:一个封装了 deno_core::JsRuntime、并带有一组用于实现 Deno 命名空间的 ops 的结构体。源码与文档一致,见 runtime/worker.rs

/// This worker is created and used by almost all
/// subcommands in Deno executable.
///
/// It provides ops available in the `Deno` namespace.
///
/// All `WebWorker`s created during program execution
/// are descendants of this worker.
pub struct MainWorker {
  pub js_runtime: JsRuntime,
  should_break_on_first_statement: bool,
  should_wait_for_inspector_session: bool,
  exit_code: ExitCode,
  bootstrap_fn_global: Option<v8::Global<v8::Function>>,
  dispatch_load_event_fn_global: v8::Global<v8::Function>,
  dispatch_beforeunload_event_fn_global: v8::Global<v8::Function>,
  dispatch_unload_event_fn_global: v8::Global<v8::Function>,
  dispatch_process_beforeexit_event_fn_global: v8::Global<v8::Function>,
  dispatch_process_exit_event_fn_global: v8::Global<v8::Function>,
  memory_trim_handle: Option<tokio::task::JoinHandle<()>>,
}

从字段设计可以读出几个实现事实:

  • MainWorker 的“人格”由两个回调集合构成:bootstrap_fn_global(JS 侧 bootstrap 入口,被 bootstrap 调用一次后消费)和五个事件分发函数——loadbeforeunloadunloadprocess:beforeExitprocess:exit。这说明 MainWorker 承担了 Node 风格的进程级事件生命周期;
  • should_break_on_first_statementshould_wait_for_inspector_session 对应 --inspect 调试场景:等待调试器连接、在第一条语句处断点;
  • Drop 实现会 abort memory_trim_handle,即 worker 销毁时终止周期性的内存整理任务。

创建 MainWorker:bootstrap_from_options

README 强调“创建 MainWorker 的实现者必须调用 MainWorker::bootstrap 来准备 JS runtime”。当前源码中这一约定收敛为组合方法 bootstrap_from_optionsruntime/worker.rs):先通过私有的 from_options 构造出 worker 和 BootstrapOptions,再立即调用 worker.bootstrap(bootstrap_options),保证创建与初始化不可分离。

from_options 接收两个大参数,正好对应 README 列举的可配置项:

1. WorkerServiceOptionsruntime/worker.rs)——宿主必须提供的服务依赖:

字段 作用
module_loader: Rc<dyn ModuleLoader> V8 请求加载 ES 模块时的回调实现;不提供则执行代码尝试加载模块会直接报错(对应 README 的“module loading implementation”)
permissions: PermissionsContainer 权限容器,多数 ops 依赖它做权限检查
fsblob_storefetch_dns_resolver 文件系统、Blob 存储、DNS 解析器
root_cert_store_provider 自定义根证书存储,对应 README 的 “CA certificate” 定制
shared_array_buffer_store 多 isolate 间共享 SharedArrayBuffer;不提供则无法序列化
compiled_wasm_module_store 多 isolate 间共享已编译的 WebAssembly.Module
v8_code_cache 模块/脚本源码的 V8 代码缓存
node_services / npm_process_state_provider 可选的 Node 兼容与 npm 集成服务

2. WorkerOptionsruntime/worker.rs)——运行时行为参数:

字段 作用
bootstrap: BootstrapOptions 注入 JS 环境的启动配置(下一节详述)
extensions: Vec<Extension> 额外注册的扩展(ops 与 JS/ESM 源);若已用快照则不应重复提供已快照化的 JS
startup_snapshot: Option<&'static [u8]> 启动时加载的 V8 快照
seed: Option<u64> 随机数生成器种子(对应 README 的 “random number generator seed”)
unsafely_ignore_certificate_errors 对指定域名忽略证书错误
create_web_worker_cb 创建 WebWorker 时必须提供的回调(README 中 WebWorker 一节的硬性要求,见后文)
format_js_error_fn: Option<Arc<FormatJsErrorFn>> 错误格式化钩子(对应 README 的 “error formatting”)
create_params isolate 创建参数,例如堆内存上限
wait_for_inspector_session 类标志 对应 README 的 “V8 inspector 与 Chrome DevTools 调试器支持”

快照分支:UnconfiguredRuntime 的两阶段构建

WorkerOptions 中还有一个值得注意的选项 unconfigured_runtime:当宿主(如 IDE 语言服务或 LSP 场景)需要复用已经创建好的运行时而不想重新构建时,可以先通过 UnconfiguredRuntime::new 建立运行时(runtime/worker.rs)。它内部用 PlaceholderModuleLoader 占位——一个所有方法都先 unwrap 一个尚未插入的真实 ModuleLoader 的空壳;随后 hydrate(module_loader) 把真实的加载器注入占位符并返回 JsRuntimefrom_options 中检测到 unconfigured_runtime 后走 hydrate 分支,而非现场构建扩展与 runtime;并且一旦请求了 trace_ops 或 op metrics,占位 runtime 会被丢弃回退到常规路径,因为这两项必须在创建期配置。

BootstrapOptions:注入 JS 环境的“配置总线”

bootstrap 阶段真正发生的事,是把 BootstrapOptions 序列化后传给 JS 侧执行 99_main.js 的引导逻辑。BootstrapOptions 定义在 runtime/worker_bootstrap.rs,其字段覆盖了 README 可配置清单中“进程级”的那一部分:

pub struct BootstrapOptions {
  pub deno_version: String,
  /// Sets `Deno.args` in JS runtime.
  pub args: Vec<String>,
  pub cpu_count: usize,
  pub log_level: WorkerLogLevel,
  pub enable_testing_features: bool,
  pub locale: String,
  pub location: Option<ModuleSpecifier>,
  pub color_level: deno_terminal::colors::ColorLevel,
  // --unstable-* flags
  pub unstable_features: Vec<i32>,
  pub user_agent: String,
  pub inspect: bool,
  /// If this is a `deno compile`-ed executable.
  pub is_standalone: bool,
  pub has_node_modules_dir: bool,
  pub argv0: Option<String>,
  pub node_debug: Option<String>,
  pub mode: WorkerExecutionMode,
  // Used by `deno serve`
  pub serve_port: Option<u16>,
  pub serve_host: Option<String>,
  pub auto_serve: bool,
  pub otel_config: OtelConfig,
  pub close_on_idle: bool,
  pub disable_offscreen_canvas: bool,
}

其中几个字段与 README 的可配置项直接对应:user_agent(“HTTP client user agent”定制)、inspect(inspector 支持)、unstable_features(细粒度 unstable 特性位)。Default 实现(worker_bootstrap.rs)透露了合理默认值的来源:cpu_countthread::available_parallelism()user_agent 格式为 Deno/{CARGO_PKG_VERSION}locale 默认 "en"mode 默认 WorkerExecutionMode::None。注释还特意提醒:默认 user_agent 用的是 crate 版本号,实现者应当提供更有意义的 UA。

序列化路径也值得细看:as_v8 通过 serde_v8 把选项打包成 BootstrapV8 元组(worker_bootstrap.rs),结构体上的注释明确要求 “Keep this in sync with 99_main.js”——即 Rust 侧的字段顺序与 JS 侧解包顺序必须一一对应。这个“Rust 元组 ↔ JS 解构”契约的 JS 一端就在 runtime/js/99_main.js,整个 runtime/js/ 目录承载了运行时引导的全部 JS 层:01_version.tsDeno.version)、90_deno_ns.jsDeno 命名空间组装)、11_workers.jsWorker 全局构造)、10_permissions.js(权限)、41_prompt.js(权限提示)等。

Worker Web API:WebWorker 与专用 OS 线程模型

README 的最后一节描述了 Worker Web API 的实现约定,源码中这三句话都能在 runtime/web_worker.rsruntime/ops/worker_host.rs 中找到印证:

1. “Worker API 由 WebWorker 结构体实现”——web_worker.rs 中的 WebWorker 持有自己的 JsRuntimenameworker_idworker_typemain_module,以及 bootstrap_fn_globalpoll_for_messages_fn 等 JS 回调。它的 Drop 实现会清理 Node resolver 的线程本地 package.json 缓存并终止内存整理任务。

2. “创建 MainWorker 时必须提供创建 Worker 的回调”——WorkerOptions::create_web_worker_cb 的类型定义在 runtime/ops/worker_host.rs

pub type CreateWebWorkerCb = dyn Fn(CreateWebWorkerArgs)
  -> (WebWorker, SendableWebWorkerHandle);

JS 侧 new Worker(url) 最终经 op 调用该回调;回调同时返回 worker 本体与一个可跨线程的 SendableWebWorkerHandle(消息通道句柄),宿主据此把 handle 注册进 op state 供后续 postMessage 使用。WebWorkerOptionsweb_worker.rs)则携带了子 worker 所需的全部参数:namemain_moduleworker_id、独立的 bootstrap: BootstrapOptions、独立的 seedstdioworker_type 等——注意 create_web_worker_cb 自身也被放入其中,使 worker 可以递归创建孙 worker,这与 README “所有 WebWorker 都是 MainWorker 的后代”的树形结构描述吻合。

3. “每个 WebWorker 都会 spawn 一条只服务于该 worker 的 OS 线程”——worker_host.rs 中可以看到 std::thread::Builder 的调用:先按 resourceLimits(若用户通过 Node 风格 API 指定了 stackSizeMb)或默认值设置栈大小(默认 DEFAULT_STACK_SIZE_MB,见 worker_host.rs 的注释:默认 4MB,以避免与 Node 行为不一致),然后 thread_builder.spawn 在新线程内构建 WebWorker、运行其事件循环,并通过 create_and_run_current_thread 驱动 future。新线程随后把自己的线程句柄存入 WorkersTable(以 worker_id 为键的 op state 表),之后主线程与 worker 线程之间的所有交互(发消息、terminateCtrl-C 控制、CPU 用量查询)都通过该表进行。

这种“一 worker 一专用线程 + 跨线程消息通道”的架构,意味着 WebWorker 与宿主线程之间不共享 isolate,跨 worker 数据传递走 postMessage 序列化通道(SharedArrayBuffer 与编译好的 wasm 模块则通过前文提到的两个共享 store 传递)。

小结:从 README 到源码的完整图景

回到 runtime/README.md 的主张,源码给出的完整证据链是:

  1. 定位deno_runtime 0.266.0 是 CLI 的瘦身后端,靠聚合 re-export(runtime/lib.rs)提供 JS 执行 + ops 绑定;
  2. 主 APIMainWorkerruntime/worker.rs)封装 JsRuntime 与五个进程级事件分发器,bootstrap_from_options 保证“创建即 bootstrap”(runtime/worker.rs);
  3. 可定制面WorkerServiceOptions 提供模块加载、权限、CA 证书等依赖注入;WorkerOptions 提供种子、错误格式化、inspector、V8 快照等开关;BootstrapOptionsruntime/worker_bootstrap.rs)负责把这些配置经 serde_v8 同步到 runtime/js/99_main.js 完成环境引导;
  4. Worker APIWebWorkerruntime/web_worker.rs)+ CreateWebWorkerCb 回调(runtime/ops/worker_host.rs)+ 每 worker 一条专用 OS 线程的线程模型,构成与 Web 标准一致的 Worker 语义。

需要再次强调 README 的稳定性警告:deno_runtime 的 API 会快速演进,本文所述字段与方法对应当前仓库版本,跨版本引用时请以该 crate 的 docs 与实际源码为准。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
982
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384