Angular 17 來(lái)了,性能大幅提升!

11 月 8 日,Angular 17 正式發(fā)布,該版本帶來(lái)了很多重要更新,包括:
- 引入了可延遲的視圖,將性能和開(kāi)發(fā)者體驗(yàn)提升到新的高度。
- 內(nèi)置控制流循環(huán)使運(yùn)行速度在公共基準(zhǔn)測(cè)試中提高了高達(dá)90%。
- 混合渲染和客戶端渲染的構(gòu)建速度分別提高了87%和67%。
- 全新的外觀體現(xiàn)了 Angular 未來(lái)的功能。
- 全新的互動(dòng)學(xué)習(xí)之旅,帶來(lái)更好的用戶體驗(yàn)。
面向未來(lái)的品牌形象
經(jīng)過(guò)過(guò)去幾個(gè)版本的快速發(fā)展,Angular 已經(jīng)迎來(lái)了全新的面貌。憑借基于信號(hào)的反應(yīng)性、水化、獨(dú)立組件、指令組合等創(chuàng)新功能,它已經(jīng)得到了數(shù)百萬(wàn)開(kāi)發(fā)人員的實(shí)戰(zhàn)檢驗(yàn)和廣泛喜愛(ài)。
盡管Angular發(fā)展迅速,但其品牌形象一直未能跟上——自AngularJS早期以來(lái)幾乎保持不變。今天,這個(gè)備受矚目的框架煥然一新,以反映其前瞻性的開(kāi)發(fā)者體驗(yàn)和卓越性能,進(jìn)一步引領(lǐng) Web 開(kāi)發(fā)的新潮流。
Angular 全新的 Logo 如下:
面向未來(lái)的文檔
除了新品牌,Angular 團(tuán)隊(duì)還為 Angular 官方文檔開(kāi)發(fā)了一個(gè)全新的主頁(yè):angular.dev。針對(duì)新的文檔網(wǎng)站,Angular 團(tuán)隊(duì)設(shè)計(jì)了一個(gè)全新的結(jié)構(gòu)、提供了全新的指南、改進(jìn)了內(nèi)容質(zhì)量,并構(gòu)建了一個(gè)互動(dòng)學(xué)習(xí)平臺(tái),以便讓開(kāi)發(fā)者在瀏覽器中按照自己的進(jìn)度學(xué)習(xí) Angular 和 Angular CLI。
新的交互式學(xué)習(xí)體驗(yàn)由 WebContainers 提供支持,可以在任何現(xiàn)代 Web 瀏覽器中使用 Angular CLI 的強(qiáng)大功能!

今天,正式推出 angular.dev 的 Beta 預(yù)覽版,并計(jì)劃在 v18 版本中將其設(shè)為 Angular 的默認(rèn)官方網(wǎng)站。
下面來(lái)看看 Angular 17 中新增的功能。
內(nèi)置控制流
為了提升開(kāi)發(fā)者的體驗(yàn),Angular 17 引入了新的塊模板語(yǔ)法,它通過(guò)簡(jiǎn)單且聲明式的 API 提供了強(qiáng)大的功能。在幕后,Angular 編譯器將此語(yǔ)法轉(zhuǎn)化為高效的 JavaScript 指令,從而實(shí)現(xiàn)了控制流、延遲加載等更多操作。
為了解決開(kāi)發(fā)人員在使用 *ngIf, *ngSwitch, 和 *ngFor 時(shí)的困擾,v17 中采用了新的塊語(yǔ)法以優(yōu)化內(nèi)置控制流。在經(jīng)過(guò)用戶研究和收集社區(qū)與合作伙伴的反饋后,決定為 Angular 創(chuàng)建一個(gè)內(nèi)置的控制流,致力于提高開(kāi)發(fā)體驗(yàn)!
內(nèi)置控制流可以:
- 更符合人體工程學(xué)的語(yǔ)法,讓代碼更加直觀,減少文檔查找的需求。
- 通過(guò)更優(yōu)化的類型檢查,提供更好的類型安全性。
- 該功能主要在構(gòu)建時(shí)起作用,最大限度地減少了運(yùn)行時(shí)占用空間,從而有可能將包大小減少30kb,同時(shí)提高 Core Web Vital 得分。
- 無(wú)需額外導(dǎo)入,該功能自動(dòng)適用于模板。
條件語(yǔ)句
先來(lái)使用*ngIf來(lái)實(shí)現(xiàn)條件語(yǔ)句。
<div *ngIf="loggedIn; else anonymousUser">
用戶已登錄
</div>
<ng-template #anonymousUser>
用戶未登錄
</ng-template>使用內(nèi)置 if 語(yǔ)句,此條件將如下所示:
@if (loggedIn) {
用戶已登錄
} @else {
用戶未登錄
}與傳統(tǒng)的 *ngIf 相比,內(nèi)置 if 語(yǔ)句的 @else 子句提供了更加簡(jiǎn)潔的條件判斷。此外,當(dāng)前的控制流使得 @else if 的實(shí)現(xiàn)變得輕而易舉,這在傳統(tǒng)的 *ngIf 中是不可能的。
在*ngSwitch中,改進(jìn)的人體工程學(xué)表現(xiàn)得更為明顯:
<div [ngSwitch]="accessLevel">
<admin-dashboard *ngSwitchCase="admin"/>
<moderator-dashboard *ngSwitchCase="moderator"/>
<user-dashboard *ngSwitchDefault/>
</div>通過(guò)內(nèi)置控制流,它變成了:
@switch (accessLevel) {
@case ('admin') { <admin-dashboard/> }
@case ('moderator') { <moderator-dashboard/> }
@default { <user-dashboard/> }
}新的控制流可以在 @switch 中的各個(gè)分支中實(shí)現(xiàn)更好的類型縮小,這在 *ngSwitch 中是不可能的。
內(nèi)置for循環(huán)
新版本還引入了內(nèi)置的 for 循環(huán),它極大地改善了開(kāi)發(fā)者體驗(yàn),并將 Angular 的渲染速度提升到了全新的高度!
其基本語(yǔ)法是:
@for (user of users; track user.id) {
{{ user.name }}
} @empty {
用戶列表為空
}我們經(jīng)常遇到由于 *ngFor 中缺少 trackBy 函數(shù)而導(dǎo)致的性能問(wèn)題。@for 的不同之處在于,為了確??焖俚谋容^性能,track 是必需的。此外,由于它只是一個(gè)表達(dá)式而不是組件類中的方法,因此使用起來(lái)更加簡(jiǎn)單。內(nèi)置的 @for 循環(huán)還提供了一個(gè)快捷方式,可以輕松遍歷零個(gè)項(xiàng)目的集合,這是通過(guò)可選的 @empty 塊實(shí)現(xiàn)的。
@for 語(yǔ)句使用了新的 diff 算法,與 *ngFor 相比具有更優(yōu)化的實(shí)現(xiàn),這使得社區(qū)框架基準(zhǔn)測(cè)試的運(yùn)行時(shí)間提高了 90%!

內(nèi)置控制流的設(shè)計(jì)目標(biāo)之一是實(shí)現(xiàn)完全自動(dòng)化的遷移。要在現(xiàn)有項(xiàng)目中嘗試它,可以使用以下命令遷移:
ng generate @angular/core:control-flow可延遲的視圖
利用新開(kāi)發(fā)的塊語(yǔ)法,創(chuàng)建了一個(gè)強(qiáng)大而高效的新機(jī)制,可以讓?xiě)?yīng)用運(yùn)行得更快??裳舆t的視圖通過(guò)前所未有的便捷性,實(shí)現(xiàn)了聲明性且強(qiáng)大的延遲加載,從而將性能和開(kāi)發(fā)者體驗(yàn)提升到了新的高度。

假設(shè)有一個(gè)博客頁(yè)面,希望實(shí)現(xiàn)用戶評(píng)論列表的延遲加載。當(dāng)前需要使用 ViewContainerRef,同時(shí)還要處理各種復(fù)雜性,如清理、錯(cuò)誤管理、占位符顯示等。處理這些邊角情況可能會(huì)涉及一些復(fù)雜的代碼,給測(cè)試和調(diào)試帶來(lái)困難。
新的可延遲視圖只需一行聲明性代碼就可以延遲加載注釋列表及其所有傳遞依賴項(xiàng):
@defer {
<comment-list />
}這一切都是通過(guò)編譯時(shí)的轉(zhuǎn)換實(shí)現(xiàn)的:Angular 找到了 @defer 塊內(nèi)使用的組件、指令和管道,將所有復(fù)雜性抽象化,生成動(dòng)態(tài)導(dǎo)入,并管理加載和狀態(tài)切換過(guò)程。
使用IntersectionObserver API來(lái)實(shí)現(xiàn)視口進(jìn)入時(shí)的延遲加載組件涉及復(fù)雜的邏輯。然而,Angular 簡(jiǎn)化了這個(gè)過(guò)程,只需添加一個(gè)可延遲的視圖觸發(fā)器即可!
@defer (on viewport) {
<comment-list />
} @placeholder {
<img src="comments-placeholder.png">
}在上面的示例中,Angular 首先渲染占位符塊的內(nèi)容。當(dāng)它在視口中可見(jiàn)時(shí), 組件就會(huì)開(kāi)始加載。加載完成后,Angular 會(huì)刪除占位符并渲染組件。
還有用于加載和錯(cuò)誤狀態(tài)的塊:
@defer (on viewport) {
<comment-list/>
} @loading {
Loading…
} @error {
Loading failed :(
} @placeholder {
<img src="comments-placeholder.png">
}Angular 為開(kāi)發(fā)者管理了大量的復(fù)雜性。
可延遲視圖提供了更多觸發(fā)器:
- on idle — 在瀏覽器閑置時(shí)延遲加載塊。
- on immediate — 自動(dòng)開(kāi)始延遲加載,不會(huì)阻塞瀏覽器。
- on timer(time) — 使用計(jì)時(shí)器延遲加載,時(shí)間可自定義。
- on viewport和on viewport(ref) — viewport 還允許為錨元素指定一個(gè)引用。當(dāng)錨元素可見(jiàn)時(shí),Angular 會(huì)延遲加載組件并渲染它。
- on interaction 和 on interaction(ref) — 允許在用戶與特定元素交互時(shí)啟動(dòng)延遲加載。
- on hover 和 on hover(ref) — 當(dāng)用戶懸停元素時(shí)觸發(fā)延遲加載。
- when expr — 允許通過(guò)返回一個(gè) promise 的表達(dá)式來(lái)指定自定義條件。
可延遲視圖還提供了在渲染依賴項(xiàng)之前預(yù)取依賴項(xiàng)的能力。添加預(yù)取就像向 defer 塊添加預(yù)取語(yǔ)句一樣簡(jiǎn)單,并且支持所有相同的觸發(fā)器。
@defer (on viewport; prefetch on idle) {
<comment-list />
}改進(jìn)的混合渲染體驗(yàn)
該版本在ng new中加入了提示,使服務(wù)端渲染(SSR)和靜態(tài)站點(diǎn)生成(SSG或預(yù)渲染)更易于使用。

或者,可以通過(guò)以下方式在新項(xiàng)目中啟用 SSR:
ng new my-app --ssr新的 @angular/ssr 包
已經(jīng)將 Angular 通用存儲(chǔ)庫(kù)移至 Angular CLI 存儲(chǔ)庫(kù),使服務(wù)端渲染成為 Angular 工具產(chǎn)品中不可或缺的一部分!
從今天開(kāi)始,要向現(xiàn)有應(yīng)用添加混合渲染支持,可以運(yùn)行以下命令:
ng add @angular/ssr此命令將生成服務(wù)器入口點(diǎn),并自動(dòng)添加 SSR 和 SSG 構(gòu)建功能,同時(shí)默認(rèn)啟用 hydration。@angular/ssr 提供了與當(dāng)前處于維護(hù)模式的 @nguniversal/express-engine 相同的功能。如果你的項(xiàng)目正在使用 express-engine,Angular CLI 將自動(dòng)將代碼更新為 @angular/ssr。
通過(guò)將 NgOptimizedImage 與帶有 DOM Hydration 的 Angular SSR 結(jié)合使用,累積布局偏移平均減少了 99.4%。
使用 SSR 部署應(yīng)用
為了進(jìn)一步增強(qiáng)開(kāi)發(fā)人員體驗(yàn),Angular 團(tuán)隊(duì)與云提供商密切合作,以實(shí)現(xiàn)順利部署到他們的平臺(tái)。
Firebase 現(xiàn)在將通過(guò)其新的框架感知CLI的早期預(yù)覽,以近乎零配置自動(dòng)識(shí)別和部署 Angular 應(yīng)用。
firebase experiments:enable webframeworks
firebase init hosting
firebase deploy框架感知的 CLI 可識(shí)別 SSR、i18n、圖像優(yōu)化等的使用,使開(kāi)發(fā)者能夠在經(jīng)濟(jì)高效的 serverless 基礎(chǔ)設(shè)施上提供高性能的 Web 應(yīng)用。
對(duì)于那些擁有復(fù)雜 Angular monorepos 或只是喜歡原生工具的人,AngularFire 允許使用 ng deploy 部署到 Firebase:
ng add @angular/fire
ng deploy為了實(shí)現(xiàn)在邊緣工作站上的部署,啟用了 Angular 服端渲染的ECMAScript模塊支持,引入了一個(gè)用于HttpClient的fetch后端,并與 CloudFlare 合作簡(jiǎn)化了這一過(guò)程。
新的生命周期 Hooks
為了提高 Angular 的 SSR 和 SSG 的性能,從長(zhǎng)遠(yuǎn)來(lái)看,Angular 團(tuán)隊(duì)希望擺脫 DOM 模擬和直接 DOM 操作。同時(shí),在大多數(shù)應(yīng)用的生命周期中,它們需要與元素交互以實(shí)例化第三方庫(kù)、測(cè)量元素大小等。
為了實(shí)現(xiàn)這一點(diǎn),Angular 團(tuán)隊(duì)開(kāi)發(fā)了一組新的生命周期掛鉤:
- afterRender — 注冊(cè)一個(gè)回調(diào),每次應(yīng)用程序完成渲染時(shí)調(diào)用。
- afterNextRender — 注冊(cè)一個(gè)回調(diào),以便在應(yīng)用程序下次完成渲染時(shí)調(diào)用。
只有瀏覽器會(huì)調(diào)用這些 Hooks,這樣就能夠?qū)⒆远x DOM 邏輯安全地直接插入到組件中。例如,如果想實(shí)例化一個(gè)圖表庫(kù),可以使用 afterNextRender:
@Component({
selector: 'my-chart-cmp',
template: `<div #chart>{{ ... }}</div>`,
})
export class MyChartCmp {
@ViewChild('chart') chartRef: ElementRef;
chart: MyChart|null;
constructor() {
afterNextRender(() => {
this.chart = new MyChart(this.chartRef.nativeElement);
}, {phase: AfterRenderPhase.Write});
}
}每個(gè)鉤子都支持一個(gè)“相位值”(例如讀取、寫(xiě)入),Angular 使用這個(gè)相位值來(lái)合理安排回調(diào)的執(zhí)行時(shí)間,從而減少頁(yè)面布局的頻繁變化,提高整體性能。
新項(xiàng)目默認(rèn)使用 Vite 和 esbuild
在v16版本中,首次引入了 esbuild 和 Vite 驅(qū)動(dòng)的構(gòu)建體驗(yàn)作為開(kāi)發(fā)預(yù)覽。自此,許多開(kāi)發(fā)人員進(jìn)行了嘗試,一些企業(yè)合作伙伴反饋稱他們的一些應(yīng)用的構(gòu)建時(shí)間縮短了67%!在 v17 中,新應(yīng)用的構(gòu)建器已經(jīng)從開(kāi)發(fā)預(yù)覽階段正式推出,并默認(rèn)應(yīng)用于所有新應(yīng)用!
此外,在使用混合渲染時(shí),更新了構(gòu)建管道。通過(guò)使用SSR和SSG,ng build的構(gòu)建速度提高了87%,ng serve的編輯刷新循環(huán)速度加快了80%。

在未來(lái)的次要版本中,將提供原理圖,以使用混合渲染(使用 SSG 或 SSR 進(jìn)行客戶端渲染)自動(dòng)遷移現(xiàn)有項(xiàng)目。
DevTools 中的依賴注入調(diào)試
去年,Angular 團(tuán)隊(duì)展示了 Angular DevTools 中依賴注入調(diào)試功能的預(yù)覽。在過(guò)去的幾個(gè)月里,實(shí)現(xiàn)了全新的調(diào)試 API,能夠插入框架的運(yùn)行時(shí)并檢查注入器樹(shù)。
基于這些 API,構(gòu)建了一個(gè)檢查用戶界面,可以預(yù)覽:
- 組件檢查器中組件的依賴關(guān)系。
- 注入器樹(shù)和依賴關(guān)系解析路徑。
- 單個(gè)注入器內(nèi)標(biāo)明的供應(yīng)商。





























