跳转到内容

能力中的概念

已发布、源试用、实验标志与开发中

发布于 更新于

能力状态描述的是一项特性在某一个引擎的发布流程中走到了哪一步、涉及哪些构建。开发中、位于实验标志之后、处于源试用和已发布这些标签分别对应不同的发布阶段和启用机制。访客浏览器是否暴露能力,仍需运行时检测。

这些标签不是宣传用语。它们对应各引擎公开流程中有名字的阶段,而每个阶段都留下开发者可以查阅的记录。

Chromium 的 launching-features 文档给出了这条路径。对每一项面向 Web 暴露的特性,第 0 步都是创建一条 ChromeStatus 条目。到原型阶段,特性负责人向 blink-dev 发送 Intent to Prototype 并开始落地代码,文档明确要求这一阶段落地的改动都位于特性标志之后。当实现作为运行时启用的特性已经可用且较为完整,文档建议进入 Dev Trials 阶段并发出 Ready for Developer Testing 邮件,但明确说明这并非必需步骤。

源试用是之后的一个可选步骤,并不等同于标志阶段。文档描述的流程是进入 Origin Trial 阶段、生成发往 blink-dev 的 Intent to Experiment 邮件,并在至少获得一位 API owner 的 LGTM 后开始试用。发布是另一道门:文档要求 Intent to Ship 获得三位 API owner 的 LGTM。

试用有时间盒。初次源试用或实验最多只能运行 12 个 Chromium 里程碑,此后每次延期最多 6 个里程碑。延期还要求草案规范、TAG 评审、signals 征询、社区反馈收集与 web-platform-tests 都有实质进展。

Chrome 的源试用指南解释启用机制。注册一项试用后,该特性会对已注册源上的所有用户启用,无需他们切换任何标志或改用其他版本的构建,但可能需要升级浏览器。令牌有三种投递方式:放在 <head> 里的 <meta http-equiv="origin-trial"> 标签、Origin-Trial HTTP 响应头,或由脚本注入。框架采用第一个有效令牌并忽略其余令牌;Chrome 会忽略无效或过期的令牌。

指南还介绍了源试用的变体。弃用试用(有时也称反向源试用)临时重新启用一项已被移除的特性;指南举的例子是自 Chrome 127 起移除的 mutation events。第三方源试用则让嵌入内容或服务的提供方在多个站点上使用该特性,而不必为每个源申请令牌。

Firefox 把标志阶段记录为一个偏好项。MDN 的实验性特性页面逐项列出该特性包含在哪些构建里(Nightly、Beta、Developer Edition 或 Release)、是否默认启用,以及用于启用它的 about:config 偏好项名称。该页面也把生命周期讲清楚了:新特性通常先出现在 Nightly,并常常在那里默认启用以便尽早收集反馈;如果没有发现重大问题,就进入 Beta 与 Developer Edition;获批的特性在稳定的 Release 通道发布,而一旦某特性在正式版中默认启用,它就会从该页面移除。

WebKit 的特性状态页面写明旧页面已撤下。它请读者从 MDN 或 Can I Use 获取支持数据,并从 WebKit Standards Positions 查阅该项目对新兴规范的立场。

可落地的换算很窄。实验标志让开发者在包含该能力的构建中启用它。源试用让已注册源为访客启用能力,无需每位访客自己切换标志或改用其他构建。Chromium 要求原型阶段落地的改动位于特性标志之后;下一阶段名为“Feature Complete behind a flag and implementation refinement”。

页面无法读取这些状态。状态看板可用于规划是否编写对应代码路径。最终运行时结果仍取决于访客浏览器暴露的能力,无论能力来自已开启的标志、有效的源试用令牌还是默认发布,代码都必须检测能力本身。

运行时检测可以判断方法是否存在,也可以校验具体载荷。第一个示例在 Web Share 不存在时提供回退;第二个示例检测所选文件,但不发起分享请求。

检测针对特性暴露出来的方法。MDN 说明 navigator.share() 需要安全上下文和瞬时用户激活,因此示例从按钮处理函数调用它(Navigator: share() method,MDN)。

<!doctype html>
<html lang="zh-CN">
<meta charset="utf-8" />
<title>能力检测</title>
<button id="share" type="button">分享本页</button>
<p id="status" role="status"></p>
<p id="fallback" hidden>
复制这个链接:<a id="page-link"></a>
</p>
<script>
const button = document.querySelector("#share");
const status = document.querySelector("#status");
const fallback = document.querySelector("#fallback");
const pageLink = document.querySelector("#page-link");
pageLink.href = location.href;
pageLink.textContent = location.href;
button.addEventListener("click", async () => {
if (!("share" in navigator)) {
fallback.hidden = false;
status.textContent = "分享不可用,请改为复制链接。";
return;
}
try {
await navigator.share({ title: document.title, url: location.href });
status.textContent = "share() 已兑现。";
} catch (error) {
status.textContent = `share() 已拒绝(${error.name})。`;
}
});
</script>
</html>

该分支在用户操作时检测能力。回退会明显改变页面,并提供无需调用另一个可选 API 的可用链接。

navigator.canShare() 返回指定数据能否交给 navigator.share() 分享。把所选 File 放进 files 数组即可检测这份载荷(Navigator: canShare() method,MDN)。

<!doctype html>
<html lang="zh-CN">
<meta charset="utf-8" />
<title>文件分享能力</title>
<label>
选择文件
<input id="file" type="file" />
</label>
<p id="file-status" role="status">尚未选择文件。</p>
<script>
const fileInput = document.querySelector("#file");
const fileStatus = document.querySelector("#file-status");
fileInput.addEventListener("change", () => {
const [file] = fileInput.files;
if (!file) {
fileStatus.textContent = "尚未选择文件。";
} else if (!("canShare" in navigator)) {
fileStatus.textContent = "文件分享校验不可用。";
} else {
const result = navigator.canShare({ files: [file] });
fileStatus.textContent = `canShare({ files }) 返回 ${result}。`;
}
});
</script>
</html>

这个页面只显示同步校验结果,不会打开分享面板,也不会宣称分享已经完成。

规范

规范状态
无。