Deno 的 deno_web 扩展全解:Web API 如何从 Rust ops 到 JS 全局对象落地
本文基于 Deno 仓库中 ext/web 目录的官方文档(ext/web/README.md)及其配套源码展开,系统讲解 deno_web 扩展的职责边界、deno_core::extension! 宏注册机制、JS 脚本加载与全局对象装配流程、Rust 侧初始化参数,并深入剖析 timers、Base64、TextEncoding、Blob 等核心 API 的底层 ops 实现。读完后,你能够完整理解一个 Web 平台 API 从 V8 桥接到用户可用全局对象的全链路,并具备在此基础上定制或扩展 deno_core 运行时能力的思路。
1. deno_web 是什么:Deno 的 Web 平台 API 集合
deno_web 是 Deno 运行时中负责实现浏览器平台级 Web API 的扩展 crate,位于 ext/web/ 目录,crate 名称为 deno_web(见 ext/web/Cargo.toml,描述为 "Collection of Web APIs")。
ext/web/README.md 开宗明义地概括了它的核心职责:
Implements timers, as well as the following APIs:
- Event
- TextEncoder
- TextDecoder
- File (Spec: https://w3c.github.io/FileAPI)
Note: Testing for text encoding is done via WPT in cli/.
也就是说,它首先提供**定时器(timers)**与 **Event 事件模型、文本编解码(TextEncoder/TextDecoder)、文件(File/Blob/FileReader)**这几组最基础的平台能力。但从实际文件清单和源码来看,它承载的远不止这些——目录中按编号组织的一批 JS 实现文件覆盖了完整的 Web 平台 API 面:
| 文件 | 提供的能力 |
|---|---|
| 00_infra.js | HTTP 解析等基础设施辅助函数 |
| 00_url.js | URL / URLSearchParams |
| 01_broadcast_channel.js | BroadcastChannel |
| 01_console.js | console |
| 01_dom_exception.js | DOMException |
| 01_mimesniff.js | MIME 类型嗅探辅助 |
| 01_urlpattern.js | URLPattern |
| 02_event.js | Event / EventTarget 及事件族 |
| 02_structured_clone.js | structuredClone 核心算法 |
| 02_timers.js | setTimeout / setInterval 等 |
| 03_abort_signal.js | AbortController / AbortSignal |
| 04_global_interfaces.js | 全局接口辅助(toStringTag 等) |
| 05_base64.js | atob / btoa |
| 06_streams.js | Web Streams(Readable/Writable/Transform) |
| 08_text_encoding.js | TextEncoder / TextDecoder |
| 09_file.js | Blob / File |
| 10_filereader.js | FileReader |
| 12_location.js | Location |
| 13_message_port.js | MessageChannel / MessagePort / structuredClone |
| 14_compression.js | CompressionStream / DecompressionStream |
| 15_performance.js | performance / PerformanceMark / Measure |
| 16_image_data.js | ImageData |
| 17_geometry.js | DOMPoint / DOMRect / DOMMatrix 等几何类型 |
| 18_css_stylesheet.js | CSSStyleSheet |
| locks.js | Web Locks API |
| webtransport.js | WebTransport |
这些编号前缀不是随意的:deno_core 的扩展加载机制要求脚本按依赖顺序加载(00_* 是最底层基础设施,01_* 依赖它,依此类推),README 中的加载示例(下文详述)也严格遵循这一顺序。
Rust 侧的实现模块与这些 JS 一一对应,见 ext/web/lib.rs 中的模块声明:blob、broadcast_channel、compression、console、geometry、message_port、stream_resource、timers、url、urlpattern 等。
2. 扩展注册机制:deno_core::extension! 宏
deno_web 与 deno_core 的集成完全由一个宏调用描述,位于 ext/web/lib.rs 的 deno_core::extension!(deno_web, ...) 中。这段宏是理解"Deno 扩展如何工作"的关键,它的每个字段都有明确职责:
deno_core::extension!(deno_web,
deps = [ deno_webidl ],
ops = [ op_base64_decode, op_encoding_new_decoder, /* ... */ ],
objects = [ geometry::DOMMatrix, image_data::ImageData, /* ... */ ],
lazy_loaded_esm = [ "locks.js", "webtransport.js" ],
lazy_loaded_js = [ "00_infra.js", "00_url.js", /* ... */ ],
options = {
blob_store: Arc<dyn BlobStoreTrait>,
maybe_location: Option<Url>,
enable_css_parser_features: bool,
bc: InMemoryBroadcastChannel,
},
state = |state, options| {
state.put(options.blob_store);
if let Some(location) = options.maybe_location {
state.put(Location(location));
}
state.put(StartTime::default());
state.put(geometry::State::new(options.enable_css_parser_features));
state.put(options.bc);
state.put(broadcast_channel::BroadcastSabStash::default());
}
);
各字段的含义:
deps = [deno_webidl]:声明本扩展依赖deno_webidl扩展(WebIDL 类型转换工具,JS 侧表现为ext:deno_webidl/00_webidl.js),与 README 中 "Dependencies" 一节一致——deno_webidl由deno_webidlcrate 提供。ops:注册全部 Rust ops(下文按子系统逐一讲解),它们是 JS 通过core.ops可访问的原生函数。objects:注册以"对象资源"形式持有的 Rust 类型(如DOMMatrix、ImageData、CSSStyleSheet、Console),这类对象在 V8 中是长生命周期对象,由 GC 追踪。lazy_loaded_js/lazy_loaded_esm:声明本扩展携带的 JS 脚本清单。普通脚本(lazy_loaded_js)按需加载;locks.js与webtransport.js走 ESM 懒加载路径,对应 README 示例中的core.createLazyLoader。options+state:定义运行时初始化时宿主必须提供的参数,并展示它们如何注入OpState(ops 共享状态容器)——Blob 存储、可选的 Location URL、定时器起点StartTime、几何状态与 BroadcastChannel 内存通道都在这里入栈。
3. 使用方式:JS 侧加载脚本并装配全局对象
ext/web/README.md 给出了在 JS 中装配整个 deno_web 扩展的标准做法:先用 core.loadExtScript 按序加载全部脚本,再把导出物挂到全局作用域。
3.1 按序加载扩展脚本
import { core } from "ext:core/mod.js";
const infra = core.loadExtScript("ext:deno_web/00_infra.js");
const url = core.loadExtScript("ext:deno_web/00_url.js");
const broadcastChannel = core.loadExtScript(
"ext:deno_web/01_broadcast_channel.js",
);
const console = core.loadExtScript("ext:deno_web/01_console.js");
const DOMException = core.loadExtScript("ext:deno_web/01_dom_exception.js");
const mimesniff = core.loadExtScript("ext:deno_web/01_mimesniff.js");
const urlPattern = core.loadExtScript("ext:deno_web/01_urlpattern.js");
const event = core.loadExtScript("ext:deno_web/02_event.js");
const structuredClone = core.loadExtScript(
"ext:deno_web/02_structured_clone.js",
);
const timers = core.loadExtScript("ext:deno_web/02_timers.js");
const abortSignal = core.loadExtScript("ext:deno_web/03_abort_signal.js");
const globalInterfaces = core.loadExtScript(
"ext:deno_web/04_global_interfaces.js",
);
const base64 = core.loadExtScript("ext:deno_web/05_base64.js");
const streams = core.loadExtScript("ext:deno_web/06_streams.js");
const encoding = core.loadExtScript("ext:deno_web/08_text_encoding.js");
const file = core.loadExtScript("ext:deno_web/09_file.js");
const fileReader = core.loadExtScript("ext:deno_web/10_filereader.js");
const location = core.loadExtScript("ext:deno_web/12_location.js");
const messagePort = core.loadExtScript("ext:deno_web/13_message_port.js");
const compression = core.loadExtScript("ext:deno_web/14_compression.js");
const performance = core.loadExtScript("ext:deno_web/15_performance.js");
const imageData = core.loadExtScript("ext:deno_web/16_image_data.js");
const loadGeometry = core.createLazyLoader("ext:deno_web/geometry.js");
const loadWebTransport = core.createLazyLoader("ext:deno_web/webtransport.js");
const geometry = loadGeometry();
const webTransport = loadWebTransport();
两个细节值得注意:
ext:协议:ext:deno_web/...是 deno_core 的扩展资源协议,脚本内容在快照(snapshot)构建期被内嵌进二进制的 V8 快照,运行时按资源 ID 取用,而不是从磁盘读取。- 懒加载器:
core.createLazyLoader用于geometry与webtransport两个脚本——首次调用时才会真正求值,避免冷启动成本。对照 ext/web/lib.rs 的lazy_loaded_esm/lazy_loaded_js清单,当前源码中几何脚本的实际文件是 ext/web/17_geometry.js(README 示例写作geometry.js,属于文档相对当前源码的轻微滞后)。
3.2 装配全局对象
加载完成后,README 给出了一段挂载示例与完整的属性表:
Object.defineProperty(globalThis, "AbortController", {
value: abortSignal.AbortController,
enumerable: false,
configurable: true,
writable: true,
});
完整的装配表如下(enumerable=false 保证这些平台对象不出现在 for...in 枚举中,与浏览器行为一致):
| Name | Value | enumerable | configurable | writeable |
|---|---|---|---|---|
| AbortController | abortSignal.AbortController | false | true | true |
| AbortSignal | abortSignal.AbortSignal | false | true | true |
| Blob | file.Blob | false | true | true |
| BroadcastChannel | broadcastChannel.BroadcastChannel | false | true | true |
| ByteLengthQueuingStrategy | streams.ByteLengthQueuingStrategy | |||
| CloseEvent | event.CloseEvent | false | true | true |
| CompressionStream | compression.CompressionStream | false | true | true |
| CountQueuingStrategy | streams.CountQueuingStrategy | |||
| CustomEvent | event.CustomEvent | false | true | true |
| DecompressionStream | compression.DecompressionStream | false | true | true |
| DOMException | DOMException | false | true | true |
| ErrorEvent | event.ErrorEvent | false | true | true |
| Event | event.Event | false | true | true |
| EventTarget | event.EventTarget | false | true | true |
| File | file.File | false | true | true |
| FileReader | fileReader.FileReader | false | true | true |
| MessageEvent | event.MessageEvent | false | true | true |
| Performance | performance.Performance | false | true | true |
| PerformanceEntry | performance.PerformanceEntry | false | true | true |
| PerformanceMark | performance.PerformanceMark | false | true | true |
| PerformanceMeasure | performance.PerformanceMeasure | false | true | true |
| PromiseRejectionEvent | event.PromiseRejectionEvent | false | true | true |
| ProgressEvent | event.ProgressEvent | false | true | true |
| ReadableStream | streams.ReadableStream | false | true | true |
| ReadableStreamDefaultReader | streams.ReadableStreamDefaultReader | |||
| TextDecoder | encoding.TextDecoder | false | true | true |
| TextEncoder | encoding.TextEncoder | false | true | true |
| TextDecoderStream | encoding.TextDecoderStream | false | true | true |
| TextEncoderStream | encoding.TextEncoderStream | false | true | true |
| TransformStream | streams.TransformStream | false | true | true |
| URL | url.URL | false | true | true |
| URLPattern | urlPattern.URLPattern | false | true | true |
| URLSearchParams | url.URLSearchParams | false | true | true |
| MessageChannel | messagePort.MessageChannel | false | true | true |
| MessagePort | messagePort.MessagePort | false | true | true |
| WritableStream | streams.WritableStream | false | true | true |
| WritableStreamDefaultWriter | streams.WritableStreamDefaultWriter | |||
| WritableStreamDefaultController | streams.WritableStreamDefaultController | |||
| ReadableByteStreamController | streams.ReadableByteStreamController | |||
| ReadableStreamBYOBReader | streams.ReadableStreamBYOBReader | |||
| ReadableStreamBYOBRequest | streams.ReadableStreamBYOBRequest | |||
| ReadableStreamDefaultController | streams.ReadableStreamDefaultController | |||
| TransformStreamDefaultController | streams.TransformStreamDefaultController | |||
| ImageData | imageData.ImageData | false | true | true |
| atob | base64.atob | true | true | true |
| btoa | base64.btoa | true | true | true |
| clearInterval | timers.clearInterval | true | true | true |
| clearTimeout | timers.clearTimeout | true | true | true |
| console | new console.Console(printer) | false | true | true |
| performance | performance.performance | true | true | true |
| reportError | event.reportError | true | true | true |
| setInterval | timers.setInterval | true | true | true |
| setTimeout | timers.setTimeout | true | true | true |
| structuredClone | messagePort.structuredClone | true | true | true |
一个值得玩味的规律:构造函数(Event、Blob…)以 enumerable: false 挂载,而函数(setTimeout、atob)与 performance 单例是 enumerable: true——这正是浏览器全局对象的实际属性描述符特征,deno_web 在这一点上刻意复刻了浏览器语义。
4. Rust 侧初始化参数
README 同时规定了宿主(如 Deno CLI 或嵌入 deno_core 的自定义运行时)在 Rust 侧必须做的事:
Then from rust, provide:
deno_web::deno_web::init(Arc<dyn BlobStoreTrait>, Option<Url>, bool, InMemoryBroadcastChannel)in theextensionsfield of yourRuntimeOptionsWhere:
Arc<dyn BlobStoreTrait>can be provided byBlobStore::default_arc()Option<Url>provides an optional base URL for certain opsboolindicates whether window features are enabled at initializationInMemoryBroadcastChannelcan be provided byDefault::default()
对照 ext/web/lib.rs 的 options 定义,四个参数与当前源码一一对应:
Arc<dyn BlobStoreTrait>:Blob 数据存储。BlobStoreTrait定义于 ext/web/blob.rs,抽象了"按 UUID 存取 Blob part、管理blob:Object URL"的职责;默认实现BlobStore提供default_arc()工厂。由于是 trait 对象,嵌入方可以替换成带内存限制或持久化的自定义存储。Option<Url>(maybe_location):可选基准 URL,用于 Location 以及 Blob Object URL 生成(insert_object_url需要maybe_location)。Some时会被封装为Location(Url)放入OpState。bool(enable_css_parser_features):当前源码中该布尔位控制是否启用 CSS 解析特性(见geometry::State::new(options.enable_css_parser_features)),影响cssparser相关能力是否开启。InMemoryBroadcastChannel(bc):进程内 BroadcastChannel 消息通道的内存实现,可用Default::default()构造。
state 闭包展示了这些参数如何落地:blob_store、Location、StartTime(timers 的时间原点)、几何状态、bc 以及 BroadcastSabStash 全部注入 OpState,随后 ops 通过 state.borrow::<T>() / state.put 读写它们。
5. 定时器:从 op_now 到 setTimeout 的全链路
README 把 timers 列为 deno_web 的头号职责。这条链路横跨 Rust 与 JS 两层。
5.1 Rust 层:时间原语
ext/web/timers.rs 只有约 57 行,却包含全部时间原语:
pub struct StartTime(Instant);
#[op2(fast)]
pub fn op_now(state: &mut OpState, #[buffer] buf: &mut [u8]) {
let start_time = state.borrow::<StartTime>();
let elapsed = start_time.elapsed();
expose_time(elapsed, buf);
}
#[op2(fast)]
pub fn op_time_origin(state: &mut OpState, #[buffer] buf: &mut [u8]) {
// https://w3c.github.io/hr-time/#dfn-estimated-monotonic-time-of-the-unix-epoch
let wall_time = SystemTime::now();
let monotonic_time = state.borrow::<StartTime>().elapsed();
let epoch = wall_time.duration_since(UNIX_EPOCH).unwrap() - monotonic_time;
expose_time(epoch, buf);
}
三个要点:
StartTime在扩展初始化时写入OpState(见第 4 节的state.put(StartTime::default())),作为单调时钟原点;op_now返回相对原点的流逝时间。op_time_origin实现了 W3C HR-Time 规范中的 "estimated monotonic time of the UNIX epoch":用当前墙钟时间减去单调流逝时间,反推出"epoch 对应的单调估计值",从而让performance.timeOrigin与Date.now()在同一时间轴上自洽。expose_time直接把秒(u32)与纳秒余数(u32)以原机字节序写入 8 字节 buffer,JS 侧用Uint32Array视图一次读出,避免跨边界的浮点舍入问题。- 第三个 op
op_defer(async(lazy)空函数)用于让 JS 侧获得一个可延后的异步 tick,服务于定时器回调的调度。
5.2 JS 层:WHATWG 语义补全
ext/web/02_timers.js 在核心 core.createTimer 之上补齐浏览器语义,文件头注释概括得很清楚:
// Web timers (setTimeout/setInterval) built directly on core.createTimer.
// Adds WHATWG-specific behavior on top:
// - webidl type coercion
// - string callback eval (WHATWG spec)
// - timer nesting depth tracking (WHATWG spec)
// - numeric timer IDs
// AsyncContext propagation across the callback boundary
以 setTimeout 为例(ext/web/02_timers.js):
- this 检查:
checkThis要求this为null/undefined/globalThis,否则抛TypeError: Illegal invocation——保证window.setTimeout.call({}, ...)这类误用会按规范报错。 - 字符串回调:若传入的不是函数,则经 WebIDL 转为字符串后用
indirectEval执行,符合 WHATWG "evaluate a string as a script" 的要求。 - AsyncContext 传播:注册时捕获
getAsyncContext(),回调执行时setAsyncContext恢复——这使await链路中的资源追踪(如 Deno 的 async locals)能跨定时器边界保持连续。 - 嵌套深度追踪:模块级
timerDepth在回调内 +1、结束后恢复,对应规范中"嵌套定时器最小延迟递增"的条款。 - 数字 ID:
createTimer返回的内部对象被存入activeTimersMap,对外暴露timer._timerId数字句柄,clearTimeout/clearInterval按 ID 查找并cancelTimer。
6. Base64:simdutf 加速的 atob / btoa
atob/btoa 看起来平凡,却是 ext/web/lib.rs 中性能工程最集中的部分。
6.1 JS 层:规范的错误语义
ext/web/05_base64.js 中,两个函数都是"webidl 参数校验 → 调 op → 错误翻译"的薄封装:
function atob(data) {
const prefix = "Failed to execute 'atob'";
webidl.requiredArguments(arguments.length, 1, prefix);
data = webidl.converters.DOMString(data, prefix, "Argument 1");
try {
return op_base64_atob(data);
} catch (e) {
if (ObjectPrototypeIsPrototypeOf(TypeErrorPrototype, e)) {
throw new DOMException(
"Failed to decode base64: invalid character",
"InvalidCharacterError",
);
}
throw e;
}
}
Rust op 抛出的 TypeError 会被翻译为浏览器的 DOMException(InvalidCharacterError);btoa 同理("string contains characters outside of the Latin1 range")。Rust 侧的错误分类定义在 ext/web/lib.rs 的 WebError 枚举,#[class("DOMExceptionInvalidCharacterError")] 等注解让 op 抛出的错误直接呈现为正确的 JS 异常类型。
6.2 Rust 层:零拷贝与 SIMD
核心 op 包括 op_base64_decode、op_base64_decode_into、op_base64_encode_from_buffer、op_base64_atob、op_base64_btoa,底层全部走 simdutf(经由 V8 暴露的 v8::simdutf):
op_base64_atob(ext/web/lib.rs):小于 8KB 的输出走栈上 8KB 缓冲解码后截断回填;大输出则直接返回解码后的新 buffer,注释明确说明这是"省掉每次大atob调用输出全量 memcpy"的优化。op_base64_encode_from_buffer:接受offset/length子区间参数,"avoiding a JS-side slice copy"——JS 不必先ArrayBuffer.slice()再编码。base64_encode_to_v8_string:输出小于 8KB 时栈上编码并new_from_one_byte构造 V8 单字节串;更大时编码进Box<[u8]>后用new_external_onebyte把所有权交给 V8(GC 时由 V8 释放),同样避免拷贝。- base64url 家族:从源码结构看,当前源码还注册了
op_base64url_decode、op_base64url_decode_into、op_base64url_encode_from_buffer(见 ext/web/lib.rs、ext/web/lib.rs),使用Base64Options::Url字母表(-_替代+/、无填充),README 的 ops 清单尚未列出这批新 op。 - 截断写入哨兵:
base64_decode_into_slice在输入非法时返回-1而非抛异常,注释解释这是为了让 JS 清洗回退路径"不用为脏输入付出抛异常的成本"。
正确性由 ext/web/lib.rs 中的单元测试锁定:RFC 4648 测试向量、64KiB 往返、Strict/Loose 末块处理差异(base64url_strict_rejects_unpadded_final_chunk 直接固化了"为什么 base64url 直解必须用 Loose"这一设计决策)、8192 字节栈/堆缓冲边界(base64url_decode_into_slice_scratch_boundary)等,覆盖面相当完整。
7. TextEncoding:encoding_rs + ASCII 快速路径
README 特别注明"Text encoding 的测试通过 cli/ 下的 WPT 用例完成"。Rust 侧 ops(ext/web/lib.rs)分为"一次性解码"和"流式解码器"两条路:
op_encoding_normalize_label:用encoding_rs::Encoding::for_label_no_replacement规范化编码标签(如UNICODE-1-1-UTF-8→utf-8),非法标签抛InvalidEncodingLabel(WebError中为range类错误)。op_encoding_decode_utf8:纯 ASCII 输入直接new_from_one_byte返回 V8 串——注释称这是"HTTP/JSON 正文、文件读取等现实主导场景",simdutf::validate_ascii的高位扫描使该检查近乎免费;非 ASCII 才走 BOM 剥离 + UTF-8 校验。解码结果超长于 V8 容量时返回BufferTooLong(RangeError),并链接到 WHATWG 编码规范与 deno 历史 issue。- 流式解码器:
op_encoding_new_decoder创建一个#[cppgc]资源TextDecoderResource(内含RefCell<Decoder>与fatal标志),op_encoding_decode携带stream参数对其增量解码——!stream时 flushing 掉解码器内部状态,这正是TextDecoder规范中stream: false与true的语义差别。 - ASCII-only 流式快速路径:
op_encoding_decode_utf8_ascii_only在输入为纯 ASCII 时直接返回 V8 串,否则返回null;JS 侧据此跳过Vec<u16>分配与 UTF-16 转换,同时保持解码器状态空闲。 - 编码(encode_into):
op_encoding_encode_into把字符串直接写进目标 buffer 并返回打包的 (read, written) 结果,还配有 V8 fast-api 变体op_encoding_encode_into_fast(输入已是 UTF-8 时按字符边界回退找截断点,纯内存拷贝)与op_encoding_encode_into_fallback(结果写入u32输出 buffer 的慢路径),三级路径兼顾了吞吐与超大量级安全。
8. Blob / File:可插拔的 BlobStore
File API(README 列名的核心能力之一,规范即 W3C FileAPI)由 ext/web/09_file.js(JS)与 ext/web/blob.rs(Rust)协作实现。Rust 侧的核心抽象:
/// Trait abstracting the blob store, allowing custom implementations
/// (e.g. with memory limits or persistence).
pub trait BlobStoreTrait: Debug + Send + Sync {
fn insert_part(&self, part: Arc<dyn BlobPart + Send + Sync>) -> Uuid;
fn get_part(&self, id: &Uuid) -> Option<Arc<dyn BlobPart + Send + Sync>>;
fn remove_part(&self, id: &Uuid) -> Option<Arc<dyn BlobPart + Send + Sync>>;
fn get_object_url(&self, url: Url) -> Option<Arc<Blob>>;
fn insert_object_url(&self, blob: Blob, maybe_location: Option<Url>) -> Url;
fn remove_object_url(&self, url: &Url);
fn clear(&self);
}
- Blob 的每个数据片段(part)以 UUID 索引存入
PartMap(HashMap<Uuid, Arc<dyn BlobPart>>),op_blob_create_part写入、op_blob_read_part/op_blob_slice_part/op_blob_clone_part读写、op_blob_remove_part清理——大文件因此可以按需分片读取而不必整体驻留。 - Object URL 生命周期:
op_blob_create_object_url生成blob:<base>/<uuid>形式的 URL(依赖第 4 节的maybe_location),op_blob_revoke_object_url释放,op_blob_from_object_url反查 Blob。 - 错误类型
BlobError(ext/web/blob.rs)区分BlobPartNotFound、SizeLargerThanBlobPart与BlobURLsNotSupported(未提供 base URL 时URL.createObjectURL不可用),均标注type错误类。
9. 其余 ops 分组速览
除上文重点剖析的子系统外,README "Provided ops" 一节列出的完整 ops 清单可按子系统归类如下(均经 Deno.ops / core.ops 访问):
- Base64:
op_base64_decode、op_base64_decode_into、op_base64_encode_from_buffer、op_base64_atob、op_base64_btoa - 编码:
op_encoding_normalize_label、op_encoding_decode_single、op_encoding_decode_utf8、op_encoding_new_decoder、op_encoding_decode、op_encoding_encode_into、op_encoding_encode_into_fallback - Blob:
op_blob_create_part、op_blob_slice_part、op_blob_read_part、op_blob_remove_part、op_blob_clone_part、op_blob_create_object_url、op_blob_revoke_object_url、op_blob_from_object_url - MessagePort:
op_message_port_create_entangled(创建纠缠的一对 MessagePort)、op_message_port_post_message、op_message_port_post_message_raw、op_message_port_recv_message(异步收包)、op_message_port_recv_message_sync - 压缩:
op_compression_new、op_compression_write、op_compression_finish(支撑 14_compression.js 的 CompressionStream/DecompressionStream;Rust 依赖 ext/web/Cargo.toml 中的brotli与flate2提供 gzip/deflate/brotli 编解码) - 时间:
op_now、op_time_origin、op_defer - 几何:
op_geometry_get_enable_css_parser_features、op_geometry_matrix_set_matrix_value、op_geometry_matrix_to_string,以及作为注册对象的DOMPointReadOnly、DOMPoint、DOMRectReadOnly、DOMRect、DOMQuad、DOMMatrixReadOnly、DOMMatrix、ImageData - 可读流资源:
op_readable_stream_resource_allocate、op_readable_stream_resource_allocate_sized、op_readable_stream_resource_get_sink、op_readable_stream_resource_write_error、op_readable_stream_resource_write_buf、op_readable_stream_resource_write_sync、op_readable_stream_resource_close、op_readable_stream_resource_await_close(把 Rust 侧资源包装成 ReadableStream 的基础设施) - URL / URLPattern:
op_url_reparse、op_url_parse、op_url_get_serialization、op_url_parse_with_base、op_url_parse_search_params、op_url_stringify_search_params、op_urlpattern_parse、op_urlpattern_process_match_input(URLPattern 由urlpatterncrate 提供) - 控制台:
op_preview_entries(源码中还注册了op_console_inspect、op_console_format_value等一批 console 格式化 ops,见 ext/web/lib.rs) - BroadcastChannel:
op_broadcast_subscribe、op_broadcast_unsubscribe、op_broadcast_serialize、op_broadcast_deserialize、op_broadcast_free、op_broadcast_send、op_broadcast_recv
从 ext/web/lib.rs 的宏注册清单还可以看到,当前源码比 README 清单多出一组 op_lock_manager_*(request/await_lock/await_steal/is_stolen/cancel/release/query),支撑 ext/web/locks.js 的 Web Locks API——README 尚未同步这一批 op。
10. 测试与基准
deno_web 的质量验证分布在三个层面,可在仓库内直接查证:
- Rust 单元测试:ext/web/lib.rs 起约 360 行
#[cfg(test)]代码,覆盖 Base64/URL 编解码的正确性向量、边界与安全断言(如base64_decode_into_asserts_output_capacity验证"输出容量不足会在内存不安全之前 panic")。 - 基准测试:ext/web/Cargo.toml 声明了四个 bench——
encoding、timers_ops、url_ops、text_decoder_stream(对应 ext/web/benches/ 目录),可单独验证高频 op 的吞吐。 - WPT 与集成测试:README 明确 TextEncoding 的规范符合性测试放在
cli/下的 WPT 用例中(仓库根下tests/目录亦含大量 Web API 集成与 WPT 适配,见 tests/wpt/ 与 tests/README.md)。
11. 小结
deno_web 展示了 Deno "Rust 提供不可信输入下的原生能力、JS 提供规范语义"的扩展分层范式:
- 注册:一个
deno_core::extension!宏声明 deps、ops、objects、JS 清单与初始化选项,ext/web/lib.rs 是该扩展的"单一事实来源"; - 加载:JS 侧
core.loadExtScript按编号顺序装配,createLazyLoader延迟非关键脚本; - 装配:50 余个全局属性以浏览器一致的属性描述符挂到
globalThis; - 实现:timers、Base64、encoding、Blob 等每条 API 都有 ops 层(含 fast-api、SIMD、零拷贝等性能路径)与 JS 层(WebIDL 校验、规范错误语义)的明确分工;
- 宿主集成:只需在
RuntimeOptions.extensions中提供BlobStoreTrait、可选Url、CSS 特性开关与InMemoryBroadcastChannel四个参数即可启用。
如果你要在自定义 deno_core 运行时上扩展 Web 能力,ext/web 是最值得逐行研读的范本;若只想查阅 API 清单与装配表,ext/web/README.md 依然是入口文档,配合 ext/web/lib.rs 的 ops 注册宏即可获得最新、最完整的能力边界。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00