- 文档
- 教程
- 知识库
【免费下载链接】developer-roadmap
Interactive roadmaps, guides and other educational content to help developers grow in their careers.
本篇文章围绕 developer-roadmap 仓库中 Angular 路线图的@defer主题文档展开,系统讲解 Angular 延迟视图(Deferrable Views)的完整机制:如何用@defer块推迟模板中组件、指令与管道的初始化,从而缩小初始包体积、提升应用启动性能,并结合interaction、viewport、timer等内置触发器与@placeholder、@loading、@error状态块给出可直接落地的模板写法。读完本文,你将掌握@defer的声明式用法、全部内置触发器的适用场景、子块参数配置,以及它与路由级懒加载、变更检测等性能手段的配合思路。
什么是@defer块
@defer是 Angular 提供的一种模板级延迟加载机制。它的核心思想是:把模板中某一部分内容的加载推迟到某个明确条件满足之后,而不是在组件初始化时立即创建。
具体来说,@defer块会推迟其内部组件、指令和管道的初始化过程(连同它们关联的样式),直到你指定的触发条件成立。由于这些依赖不再随宿主组件首屏一同初始化,浏览器需要下载、解析并执行的初始代码量随之下降,应用的启动性能与首屏渲染速度都会受益。
正如 roadmaps/angular/content/defer@ONy-0olujU_FGZM7Wvfr2.md 所总结的,你可以使用内置的interaction(交互)、visibility(可见性/视口)或time(定时)等触发器来控制加载时机,同时通过占位(placeholder)与加载(loading)状态向用户展示内容拉取过程中的界面反馈。
同目录下的 deferrable-views@CYjsXIOWtP5DJmYS-qR-s.md 进一步补充了关键细节:被延迟的依赖包括组件、指令、管道,以及它们关联的任何 CSS;使用方式是在组件模板中用@defer块声明式地包裹一段模板,并在块中指定加载条件。因此@defer也被官方称为"Deferrable Views"(可延迟视图)。
为什么要延迟:性能收益的本质
理解@defer的价值,需要先看清楚它优化的是什么环节:
- 初始包体积(Initial Bundle Size):被
@defer包裹的组件、指令、管道会从宿主组件的即时依赖中剥离,编译器把它们拆分为可按需加载的独立代码块。首屏不需要的代码不再进入初始 JS 包,浏览器下载量变小。 - 启动性能(Startup Performance):初始化的组件数量变少,Angular 启动时执行的实例化、依赖注入与变更检测工作相应减少,应用可以更快进入可交互状态。
- 首屏渲染:非关键内容(评论区、图表、播放器等)可以等视口滚动到附近、用户发生交互或浏览器空闲后再渲染,避免阻塞关键路径。
值得注意的是,@defer与路由级懒加载(Lazy Loading)定位不同。路由级懒加载以模块/路由为粒度,如 lazy-loading-modules@bLERvEERmNI5AgxtEYokZ.md 所述,默认情况下 NgModule 是急切加载的,懒加载是"按需加载 NgModule"的设计模式;而@defer是在单个组件模板内部以更细粒度延迟部分依赖,两者可以叠加使用——路由懒加载控制页面级代码何时到达,@defer再控制页面内非核心区块何时初始化。
基本用法:声明式包裹模板
@defer的使用方式是纯声明式的:在组件模板中写一个@defer块,把需要延迟的内容放进去,再配合若干子块提供过渡状态。
一个最简示例:
@defer { <heavy-component /> } @placeholder { <div>内容加载中,请稍候…</div> } @loading { <app-spinner /> }这里发生了三件事:
<heavy-component />及其依赖不会被立即初始化,它的代码被拆分为独立 chunk;- 在触发条件满足之前,模板渲染
@placeholder块中的占位内容; - 当内容开始拉取时,
@loading块中的加载提示显示给用户。
被延迟的内容加载完成后,Angular 会移除占位/加载块并渲染真正的延迟内容。你也可以在@defer内部继续使用@if、@for等控制流块,组合出更复杂的按需渲染逻辑。
内置触发器:精准控制加载时机
触发器的写法是把条件放在@defer块名后的括号里:@defer (on 触发器)。原文档明确提到的三类触发能力,在 Angular 中对应以下内置触发器:
| 触发器 | 触发时机 | 典型场景 |
|---|---|---|
on idle | 浏览器空闲时(利用requestIdleCallback一类的空闲机制) | 后台上报组件、非交互统计类小部件 |
on immediate | 页面加载后立即开始,但依然异步、不阻塞首屏 | 首屏后尽快可见的内容 |
on timer(1s) | 指定的毫秒数之后(示例为 1 秒) | 延迟动画、稍后出现的浮层 |
on viewport | 元素进入视口(浏览器可见区域) | 长列表下方的评论区、懒加载图片/图表 |
on interaction | 用户与占位区域交互(点击、触摸、键盘操作) | 视频播放器、地图、重型表单 |
on hover | 鼠标悬停在占位区域 | 悬停预览、详情浮层 |
除了直接作用于占位区域,还可以通过模板引用变量(#ref)把触发条件绑定到模板中的任意元素,例如:
<div #target>下拉到此处附近再加载</div> @defer (on viewport(target)) { <charts-dashboard /> } @placeholder { <div>滚动接近目标区域后加载图表</div> }类似的写法同样适用于on interaction(ref)与on hover(ref):只要用户与#ref指向的元素交互,就触发加载。
多个触发器可以组合,用分号分隔,满足任一条件即加载:
@defer (on viewport; on idle) { <ad-banner /> }预取(Prefetch):提前下载、延后渲染
在需要更精细控制的场景下,@defer还支持prefetch变体:提前下载代码,但推迟到主触发条件满足时才渲染。常见的组合是"资源预取 + 条件触发":
@defer (on interaction; prefetch on viewport) { <video-player /> } @placeholder { <button>点击播放</button> }上面这个例子表示:当播放器进入视口时先预取代码,但真正的渲染要等用户点击占位按钮后才进行。这样既保证了点击时几乎无等待,又不占用首屏资源。prefetch可与所有内置触发器组合,如prefetch on idle、prefetch on timer(2s)等。
占位、加载与错误状态块的参数
@defer的过渡状态块不止是简单的占位,各自支持可调参数,用于控制展示时长,避免闪烁:
@defer (on viewport) { <comments-section /> } @placeholder (minimum 500ms) { <div>占位骨架屏</div> } @loading (after 100ms; minimum 1s) { <app-spinner /> } @error { <div>加载失败,请重试</div> }@placeholder (minimum 500ms):占位内容至少展示 500ms。这一参数可以防止"内容瞬间加载完成,占位一闪而过"造成的布局跳动;@loading (after 100ms; minimum 1s):等待 100ms 后才显示加载状态(避免慢速网络下闪一下加载提示),且一旦显示至少持续 1s;@error:当延迟块的代码加载失败或渲染抛出错误时,显示该块内容,便于做降级处理。
这些参数共同保证了从"占位 → 加载 → 就绪/失败"的过渡平滑可控。
底层原理与依赖范围
从机制层面看,@defer依赖 Angular 编译器的配合:编译器识别出模板中被@defer包裹的依赖后,会为它们生成独立的加载逻辑与代码分块,运行时按触发条件动态拉取并初始化。这也是它能在"不改变组件间数据流与依赖注入"的前提下实现延迟的关键——被延迟内容就绪后,渲染结果与普通模板并无差别。
值得注意的边界是:@defer延迟的是块内组件的初始化与相关 CSS 的加载,块外模板不受影响。因此适合把"首屏必需"与"次要内容"在模板层面清晰划分,而不是整页延迟。若要进一步优化图片这类资源的加载,可以配合路线图中的 image-optimization@1WIKjn3nxYDMIhBL17aYQ.md(NgOptimizedImage)一起使用;若关心延迟渲染对变更检测的影响,可参考 change-detection@_-mTs_FMeob-ZGK-bb3j-.md 中的运行时性能优化思路。
测试与调试要点
@defer是模板级声明,测试时可以通过控制触发条件来验证各状态块。常规做法包括:
- 对
on interaction类触发:在测试中模拟点击/键盘事件,断言占位内容先渲染、延迟内容随后出现; - 对
on viewport类触发:模拟元素进入视口(如设置合理的测试容器尺寸或调用对应滚动逻辑)后断言内容加载; - 对
on timer(...)类触发:使用假时钟(fake timers)快进到指定时间,验证加载行为; - 分别断言
@placeholder、@loading与@error分支在对应条件下的渲染结果,覆盖成功与失败两条路径。
调试时重点观察 DevTools 中的网络面板与代码分割(code-splitting)产物,确认延迟内容确实以独立 chunk 出现、且只在触发条件满足后才被请求。
在 developer-roadmap Angular 路线图中的定位
在 roadmaps/angular/content 目录下,@defer与 deferrable-views@CYjsXIOWtP5DJmYS-qR-s.md 构成该主题的一对核心文档,前者聚焦@defer块的触发与状态机制,后者补充了延迟依赖的完整范围(组件、指令、管道与关联 CSS)。二者共同位于 Angular 性能优化知识群中,与路由懒加载(lazy-loading-modules@bLERvEERmNI5AgxtEYokZ.md)、运行时性能优化(change-detection@_-mTs_FMeob-ZGK-bb3j-.md)以及图片加载优化(image-optimization@1WIKjn3nxYDMIhBL17aYQ.md)等主题互为补充,共同构成一份完整的 Angular 性能优化实践脉络。开发者可沿这条路线图依次掌握"路由级懒加载 → 模板级@defer→ 细粒度资源优化"的层层递进方案。
- 文档
- 教程
- 知识库
【免费下载链接】developer-roadmap
Interactive roadmaps, guides and other educational content to help developers grow in their careers.
相关推荐
Angular 可延迟视图实战:用 @placeholder、@loading 与 @error 管理加载状态
Angular 可延迟视图实战:用 @placeholder、@loading 与 @error 管理加载状态 导读 :在 Angular 应用中, @defe
前端Web框架Angular 可延迟视图进阶:用 `@defer` 触发器(on / when)精准控制懒加载时机
Angular 可延迟视图进阶:用 @defer 触发器(on / when)精准控制懒加载时机 本篇文章以 Angular 官方交互式教程中的「Deferra
前端Web框架Angular 可延迟视图(Deferrable Views)实战:@defer 语法、空闲加载机制与懒加载分块原理
Angular 可延迟视图(Deferrable Views)实战:@defer 语法、空闲加载机制与懒加载分块原理 Angular 的 deferrable
前端Web框架
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考