应使用performance.getEntriesByType("resource")过滤initiatorType === "parser"的条目,提取name、duration、transferSize等字段,在DOMContentLoaded后立即采集,结合模块加载行为与真实URL构建依赖图,而非依赖DOM顺序或静态标签分析。

怎么用 performance API 提取真实 parser 依赖链
浏览器不会把 HTML 里写的 <link> 和 <script></script> 自动变成有向图,得靠 performance.getEntriesByType("resource") 拿到运行时真实加载行为。只过滤 initiatorType === "parser" 的条目,才是 CRP 里真正阻塞解析的节点。
常见错误:用 document.querySelectorAll("script, link[rel=stylesheet]") 遍历 DOM —— 这会把 async、defer、preload 全当关键节点,实际它们不参与拓扑排序。
-
performance.getEntriesByType("resource")返回的是加载完成后的快照,必须在DOMContentLoaded后立即采集,否则部分资源可能已被垃圾回收 - 每个条目要提取
name(真实 URL)、initiatorType、duration,再结合transferSize判断是否真卡在执行而非下载 - 对
type="module"脚本,需额外调用import.meta.url获取其静态 import 路径,但注意构建后路径常被重写,应以performance.getEntriesByName("xxx.mjs")[0].name为准
为什么不能直接按 DOM 顺序建图
DOM 树顺序 ≠ 执行顺序,更不等于依赖关系。比如一个 <script async src="lib.js"></script> 写在 最前,实际可能比后面 defer 脚本还晚执行;<link rel="stylesheet"> 后面紧跟着的 <script></script> 会被阻塞,但 DOM 里它们只是兄弟节点,没有边关系。
真正起点是 document,终点是 DOMContentLoaded,中间边由三类事件共同决定:load(资源下载完成)、readystatechange(HTML 解析状态变更)、CSSOM 构建完成(无公开 API,只能靠后续脚本执行延迟反推)。
立即学习“前端免费学习笔记(深入)”;
- 内联
<script>console.log(1)</script>是叶子节点,但它依赖前面所有 parser-blocking 资源完成,不能当孤立节点处理 -
srcset必须用currentSrc取当前设备匹配项,不能按属性值直接建边 - 自定义属性如
data-module或 Web Component 的data-image,不显式配置提取规则就会被忽略
拓扑排序时怎么处理 modulepreload 和动态 import
modulepreload 只能展开静态 import 链,对运行时拼接路径完全无效。它不是“预加载 + 预执行”,而是“预 fetch + 预解析”,且只认字面量字符串。
典型失效场景:import(`./${env}/config.mjs`)、import('./chunk-' + id + '.mjs')、服务器返回 404 或 MIME 类型错误都会导致链式中断,且控制台静默无报错。
- 动态 import 必须由 JS 主动采集:监听
import()调用,用performance.mark()+performance.measure()记录起止,再关联到对应资源 entry -
modulepreload不该作为图中节点加入,它只是优化手段,不改变依赖结构;把它当节点会误判执行顺序 - CORS 不一致会直接破坏模块链:
<script type="module" src="/a.mjs" crossorigin="anonymous"></script>和import "./b.mjs"若后者没配crossorigin,加载失败但无提示
拓扑图渲染时哪些字段必须带
轻量数据结构必须含 id、type("html"/"style"/"script")、blocking(布尔值)、dependsOn(字符串数组),缺一不可。仅靠 id 和 dependsOn 不足以驱动 SVG 渲染,因为阻塞边和非阻塞边样式不同,type 决定颜色,blocking 决定边线型和节点边框粗细。
容易漏掉的点:dependsOn 必须存上游资源 id,不是 URL;URL 可能带查询参数或 hash,而 id 应标准化为文件名(如 "main.css" 而非 "main.css?v=1.2.3")。
-
preload不参与dependsOn字段构建,它不构成依赖边 - 多个
parser请求串连(如 A.css → B.css → app.js)表明隐式依赖链,B.css 的dependsOn必须包含 A.css,不能只写 app.js 依赖 B.css -
viewBox="0 0 1200 600"是硬性要求,避免手动写像素坐标导致响应式失效
dependsOn 关系必须从 Network 面板的 Initiator 链反推,而不是靠肉眼数 <link> 出现位置。



















