customelements.define 中禁止在 constructor 或 connectedcallback 开头直接 queryselector 查找其他组件,应延后查询并检查 customelements.get 是否已注册;data-prereq 是声明式标记而非 css 选择器;需防循环依赖、设超时上限、weakmap 缓存须与生命周期对齐。

customElements.define 里别急着查其他组件
在自定义元素内部,constructor 或 connectedCallback 开头就调用 document.querySelector('auth-provider') 是高频错误。此时目标组件可能还没定义、DOM 还没挂载完,结果是 null 或静默失败。
必须把查询逻辑延后:
- 用
requestIdleCallback或setTimeout(() => {}, 0)推迟到微任务之后 - 先检查是否已注册:
customElements.get('auth-provider') !== undefined,不能只查 DOM - 若未就绪,设
this.setAttribute('data-waiting-for', 'auth-provider')并提前返回,避免重复执行
data-prereq 不是 CSS 选择器,是声明式标记
data-prereq="user-avatar,plan-selector" 看起来像 selector,但它只是字符串标识——不参与 DOM 查询,也不触发样式匹配。真正解析靠集中管理器(比如 window.$deps)按 data-component-id 查找,而非 id 属性。
关键点:
-
data-component-id必须唯一,推荐用crypto.randomUUID()生成 - 下游组件响应事件时,只更新自身所在节点,不要全量扫描 DOM
- 别把
data-prereq当成可直接 query 的 selector,否则会漏匹配或误匹配
循环依赖得运行时检测,不能靠人工 review
A 等 B 就绪、B 又等 A 提供配置,这种死锁不会报错,只会卡在 pending 状态。靠代码审查几乎发现不了。
实际做法:
- 在协调器中维护一个依赖路径栈,每次触发
component:ready前,检查当前组件是否已在栈中出现过 - 检测到循环时,主动降级:让 B 忽略 A 的配置,用默认值初始化,并发
component:degraded事件 - 每个等待必须设超时上限——5 秒是经验阈值,超时后清空
data-waiting-for,加data-timeout="true"方便定位
WeakMap 缓存必须和生命周期对齐
最容易被忽略的内存泄漏点:用 WeakMap 缓存组件引用时,没在 disconnectedCallback 里手动 weakMap.delete(this)。
后果是:
- 组件已卸载,但 WeakMap 仍持引用,GC 不回收
- 内存占用持续增长,掩盖真正的依赖问题(比如本该释放却还在监听)
- 后续重挂载时,旧缓存可能干扰新实例状态
WeakMap 不是“自动安全”的银弹,它只解决强引用问题,不解决生命周期错配。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











