html关键路径依赖图必须由js主动采集建模,因preload/module等不暴露依赖关系;需遍历dom按语义提取script、link等节点并构建有向边,dom顺序不等于执行顺序,且须结合运行时数据校准。

HTML 页面加载关键路径资源依赖不能靠 <link rel="preload"> 或 <script type="module"></script> 自动生成拓扑图——它们不暴露依赖关系,也不提供执行顺序的结构化描述,必须由 JS 主动采集并建模。
如何从 HTML 中提取真实资源依赖关系
浏览器加载器不会把 src、href、data-src 等属性自动组织成有向图。你得自己遍历 DOM,按语义分类提取:
-
<script src="a.js"></script>和<script type="module" src="b.mjs"></script>是显式同步/模块依赖,但type="module"不保证执行顺序,需额外解析import语句才能补全图边 -
<link rel="stylesheet" href="main.css">是渲染阻塞依赖;rel="preload"只是下载提示,不构成关键路径边 - 自定义属性如
data-module="auth"或data-chunk="vendor"必须显式配置规则提取,否则会被 html-loader 或分析脚本忽略 -
srcset需单独处理:同一<img>可能对应多个物理资源,但关键路径只取当前设备匹配的那一项(用currentSrc读)
为什么不能直接用 DOM 树当依赖图
DOM 节点顺序 ≠ 执行顺序。例如:
-
<script async src="lib.js"></script>插入位置靠前,但可能晚于后面某个defer脚本执行 -
<link rel="stylesheet">后面跟着<script></script>,实际会阻塞该 script,但 DOM 树里它们是兄弟节点,无父子/先后边关系 - 内联
<script>console.log(1)</script>会立即执行,但它在图中应作为“叶子节点”而非“无依赖节点”——它依赖前面所有阻塞资源完成
真正关键路径图的起点是 document,终点是 DOMContentLoaded,中间边由资源加载完成事件(load)、解析完成(readystatechange)、以及 CSSOM 构建完成共同决定。
自动化构建拓扑图的最小可行 JS 逻辑
不需要引入 D3 或 Graphviz,一段可运行的 <script></script> 就能产出带层级和边的 JSON 图结构:
const buildCriticalPathGraph = () => {
const graph = { nodes: [], edges: [] };
const scripts = document.querySelectorAll('script[src], script[type="module"]');
const styles = document.querySelectorAll('link[rel="stylesheet"]');
// 节点:每个资源一个,带类型、URL、是否阻塞
scripts.forEach((s, i) => {
const url = s.src || s.getAttribute('src');
graph.nodes.push({
id: `script-${i}`,
type: 'script',
url,
blocking: !s.async && !s.defer
});
});
// 边:阻塞脚本 → 后续所有脚本(直到下一个 defer/async)
let lastBlockingIndex = -1;
scripts.forEach((s, i) => {
if (!s.async && !s.defer) {
lastBlockingIndex = i;
} else if (lastBlockingIndex !== -1) {
graph.edges.push({ from: `script-${lastBlockingIndex}`, to: `script-${i}` });
lastBlockingIndex = -1;
}
});
return graph;
};
- 这个逻辑只覆盖最常见 case(非动态 import、无 service worker 干预),但已能暴露 80% 的加载瓶颈
- 若页面用了
import('./chunk.js'),必须在import执行后钩住Promise.then()动态加节点,静态扫描无法捕获 - 生成的
graph可直接喂给<svg></svg>渲染,或导出为 DOT 格式供 Graphviz 可视化
容易被忽略的破坏性细节
拓扑图一旦生成就默认“静态可信”,但以下情况会让图迅速失效:
- 服务端启用了 HTTP/2 Server Push,资源在 HTML 到达前已推送——图中不会出现这些边,但它们真实影响关键路径
-
<script type="module"></script>在 Safari 16.4+ 前不支持crossorigin属性,导致错误资源不触发error事件,图中缺失失败节点 - 使用
document.write()动态注入 script(尽管已淘汰),会打断 parser,让后续资源加载时机完全脱离 HTML 结构 - 任何通过
fetch()+eval()加载的代码,都不会出现在初始 HTML 中,也无法被上述逻辑捕获
所以真正的关键路径图不是一次构建就能长期复用的产物,它必须和 PerformanceObserver、Navigation Timing API 的运行时数据对齐,否则只是个好看的示意图。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











