Angular 17 來了,性能大幅提升!
11 月 8 日,Angular 17 正式發(fā)布,該版本帶來了很多重要更新,包括:
- 引入了可延遲的視圖,將性能和開發(fā)者體驗提升到新的高度。
- 內(nèi)置控制流循環(huán)使運(yùn)行速度在公共基準(zhǔn)測試中提高了高達(dá)90%。
- 混合渲染和客戶端渲染的構(gòu)建速度分別提高了87%和67%。
- 全新的外觀體現(xiàn)了 Angular 未來的功能。
- 全新的互動學(xué)習(xí)之旅,帶來更好的用戶體驗。
面向未來的品牌形象
經(jīng)過過去幾個版本的快速發(fā)展,Angular 已經(jīng)迎來了全新的面貌。憑借基于信號的反應(yīng)性、水化、獨(dú)立組件、指令組合等創(chuàng)新功能,它已經(jīng)得到了數(shù)百萬開發(fā)人員的實戰(zhàn)檢驗和廣泛喜愛。
盡管Angular發(fā)展迅速,但其品牌形象一直未能跟上——自AngularJS早期以來幾乎保持不變。今天,這個備受矚目的框架煥然一新,以反映其前瞻性的開發(fā)者體驗和卓越性能,進(jìn)一步引領(lǐng) Web 開發(fā)的新潮流。
Angular 全新的 Logo 如下:
面向未來的文檔
除了新品牌,Angular 團(tuán)隊還為 Angular 官方文檔開發(fā)了一個全新的主頁:angular.dev。針對新的文檔網(wǎng)站,Angular 團(tuán)隊設(shè)計了一個全新的結(jié)構(gòu)、提供了全新的指南、改進(jìn)了內(nèi)容質(zhì)量,并構(gòu)建了一個互動學(xué)習(xí)平臺,以便讓開發(fā)者在瀏覽器中按照自己的進(jìn)度學(xué)習(xí) Angular 和 Angular CLI。
新的交互式學(xué)習(xí)體驗由 WebContainers 提供支持,可以在任何現(xiàn)代 Web 瀏覽器中使用 Angular CLI 的強(qiáng)大功能!
今天,正式推出 angular.dev 的 Beta 預(yù)覽版,并計劃在 v18 版本中將其設(shè)為 Angular 的默認(rèn)官方網(wǎng)站。
下面來看看 Angular 17 中新增的功能。
內(nèi)置控制流
為了提升開發(fā)者的體驗,Angular 17 引入了新的塊模板語法,它通過簡單且聲明式的 API 提供了強(qiáng)大的功能。在幕后,Angular 編譯器將此語法轉(zhuǎn)化為高效的 JavaScript 指令,從而實現(xiàn)了控制流、延遲加載等更多操作。
為了解決開發(fā)人員在使用 *ngIf, *ngSwitch, 和 *ngFor 時的困擾,v17 中采用了新的塊語法以優(yōu)化內(nèi)置控制流。在經(jīng)過用戶研究和收集社區(qū)與合作伙伴的反饋后,決定為 Angular 創(chuàng)建一個內(nèi)置的控制流,致力于提高開發(fā)體驗!
內(nèi)置控制流可以:
- 更符合人體工程學(xué)的語法,讓代碼更加直觀,減少文檔查找的需求。
- 通過更優(yōu)化的類型檢查,提供更好的類型安全性。
- 該功能主要在構(gòu)建時起作用,最大限度地減少了運(yùn)行時占用空間,從而有可能將包大小減少30kb,同時提高 Core Web Vital 得分。
- 無需額外導(dǎo)入,該功能自動適用于模板。
條件語句
先來使用*ngIf來實現(xiàn)條件語句。
<div *ngIf="loggedIn; else anonymousUser">
用戶已登錄
</div>
<ng-template #anonymousUser>
用戶未登錄
</ng-template>
使用內(nèi)置 if 語句,此條件將如下所示:
@if (loggedIn) {
用戶已登錄
} @else {
用戶未登錄
}
與傳統(tǒng)的 *ngIf 相比,內(nèi)置 if 語句的 @else 子句提供了更加簡潔的條件判斷。此外,當(dāng)前的控制流使得 @else if 的實現(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>
通過內(nèi)置控制流,它變成了:
@switch (accessLevel) {
@case ('admin') { <admin-dashboard/> }
@case ('moderator') { <moderator-dashboard/> }
@default { <user-dashboard/> }
}
新的控制流可以在 @switch 中的各個分支中實現(xiàn)更好的類型縮小,這在 *ngSwitch 中是不可能的。
內(nèi)置for循環(huán)
新版本還引入了內(nèi)置的 for 循環(huán),它極大地改善了開發(fā)者體驗,并將 Angular 的渲染速度提升到了全新的高度!
其基本語法是:
@for (user of users; track user.id) {
{{ user.name }}
} @empty {
用戶列表為空
}
我們經(jīng)常遇到由于 *ngFor 中缺少 trackBy 函數(shù)而導(dǎo)致的性能問題。@for 的不同之處在于,為了確??焖俚谋容^性能,track 是必需的。此外,由于它只是一個表達(dá)式而不是組件類中的方法,因此使用起來更加簡單。內(nèi)置的 @for 循環(huán)還提供了一個快捷方式,可以輕松遍歷零個項目的集合,這是通過可選的 @empty 塊實現(xiàn)的。
@for 語句使用了新的 diff 算法,與 *ngFor 相比具有更優(yōu)化的實現(xiàn),這使得社區(qū)框架基準(zhǔn)測試的運(yùn)行時間提高了 90%!
內(nèi)置控制流的設(shè)計目標(biāo)之一是實現(xiàn)完全自動化的遷移。要在現(xiàn)有項目中嘗試它,可以使用以下命令遷移:
ng generate @angular/core:control-flow
可延遲的視圖
利用新開發(fā)的塊語法,創(chuàng)建了一個強(qiáng)大而高效的新機(jī)制,可以讓應(yīng)用運(yùn)行得更快??裳舆t的視圖通過前所未有的便捷性,實現(xiàn)了聲明性且強(qiáng)大的延遲加載,從而將性能和開發(fā)者體驗提升到了新的高度。
假設(shè)有一個博客頁面,希望實現(xiàn)用戶評論列表的延遲加載。當(dāng)前需要使用 ViewContainerRef,同時還要處理各種復(fù)雜性,如清理、錯誤管理、占位符顯示等。處理這些邊角情況可能會涉及一些復(fù)雜的代碼,給測試和調(diào)試帶來困難。
新的可延遲視圖只需一行聲明性代碼就可以延遲加載注釋列表及其所有傳遞依賴項:
@defer {
<comment-list />
}
這一切都是通過編譯時的轉(zhuǎn)換實現(xiàn)的:Angular 找到了 @defer 塊內(nèi)使用的組件、指令和管道,將所有復(fù)雜性抽象化,生成動態(tài)導(dǎo)入,并管理加載和狀態(tài)切換過程。
使用IntersectionObserver API來實現(xiàn)視口進(jìn)入時的延遲加載組件涉及復(fù)雜的邏輯。然而,Angular 簡化了這個過程,只需添加一個可延遲的視圖觸發(fā)器即可!
@defer (on viewport) {
<comment-list />
} @placeholder {
<img src="comments-placeholder.png">
}
在上面的示例中,Angular 首先渲染占位符塊的內(nèi)容。當(dāng)它在視口中可見時, 組件就會開始加載。加載完成后,Angular 會刪除占位符并渲染組件。
還有用于加載和錯誤狀態(tài)的塊:
@defer (on viewport) {
<comment-list/>
} @loading {
Loading…
} @error {
Loading failed :(
} @placeholder {
<img src="comments-placeholder.png">
}
Angular 為開發(fā)者管理了大量的復(fù)雜性。
可延遲視圖提供了更多觸發(fā)器:
- on idle — 在瀏覽器閑置時延遲加載塊。
- on immediate — 自動開始延遲加載,不會阻塞瀏覽器。
- on timer(time) — 使用計時器延遲加載,時間可自定義。
- on viewport和on viewport(ref) — viewport 還允許為錨元素指定一個引用。當(dāng)錨元素可見時,Angular 會延遲加載組件并渲染它。
- on interaction 和 on interaction(ref) — 允許在用戶與特定元素交互時啟動延遲加載。
- on hover 和 on hover(ref) — 當(dāng)用戶懸停元素時觸發(fā)延遲加載。
- when expr — 允許通過返回一個 promise 的表達(dá)式來指定自定義條件。
可延遲視圖還提供了在渲染依賴項之前預(yù)取依賴項的能力。添加預(yù)取就像向 defer 塊添加預(yù)取語句一樣簡單,并且支持所有相同的觸發(fā)器。
@defer (on viewport; prefetch on idle) {
<comment-list />
}
改進(jìn)的混合渲染體驗
該版本在ng new中加入了提示,使服務(wù)端渲染(SSR)和靜態(tài)站點(diǎn)生成(SSG或預(yù)渲染)更易于使用。
或者,可以通過以下方式在新項目中啟用 SSR:
ng new my-app --ssr
新的 @angular/ssr 包
已經(jīng)將 Angular 通用存儲庫移至 Angular CLI 存儲庫,使服務(wù)端渲染成為 Angular 工具產(chǎn)品中不可或缺的一部分!
從今天開始,要向現(xiàn)有應(yīng)用添加混合渲染支持,可以運(yùn)行以下命令:
ng add @angular/ssr
此命令將生成服務(wù)器入口點(diǎn),并自動添加 SSR 和 SSG 構(gòu)建功能,同時默認(rèn)啟用 hydration。@angular/ssr 提供了與當(dāng)前處于維護(hù)模式的 @nguniversal/express-engine 相同的功能。如果你的項目正在使用 express-engine,Angular CLI 將自動將代碼更新為 @angular/ssr。
通過將 NgOptimizedImage 與帶有 DOM Hydration 的 Angular SSR 結(jié)合使用,累積布局偏移平均減少了 99.4%。
使用 SSR 部署應(yīng)用
為了進(jìn)一步增強(qiáng)開發(fā)人員體驗,Angular 團(tuán)隊與云提供商密切合作,以實現(xiàn)順利部署到他們的平臺。
Firebase 現(xiàn)在將通過其新的框架感知CLI的早期預(yù)覽,以近乎零配置自動識別和部署 Angular 應(yīng)用。
firebase experiments:enable webframeworks
firebase init hosting
firebase deploy
框架感知的 CLI 可識別 SSR、i18n、圖像優(yōu)化等的使用,使開發(fā)者能夠在經(jīng)濟(jì)高效的 serverless 基礎(chǔ)設(shè)施上提供高性能的 Web 應(yīng)用。
對于那些擁有復(fù)雜 Angular monorepos 或只是喜歡原生工具的人,AngularFire 允許使用 ng deploy
部署到 Firebase:
ng add @angular/fire
ng deploy
為了實現(xiàn)在邊緣工作站上的部署,啟用了 Angular 服端渲染的ECMAScript模塊支持,引入了一個用于HttpClient
的fetch后端,并與 CloudFlare 合作簡化了這一過程。
新的生命周期 Hooks
為了提高 Angular 的 SSR 和 SSG 的性能,從長遠(yuǎn)來看,Angular 團(tuán)隊希望擺脫 DOM 模擬和直接 DOM 操作。同時,在大多數(shù)應(yīng)用的生命周期中,它們需要與元素交互以實例化第三方庫、測量元素大小等。
為了實現(xiàn)這一點(diǎn),Angular 團(tuán)隊開發(fā)了一組新的生命周期掛鉤:
- afterRender — 注冊一個回調(diào),每次應(yīng)用程序完成渲染時調(diào)用。
- afterNextRender — 注冊一個回調(diào),以便在應(yīng)用程序下次完成渲染時調(diào)用。
只有瀏覽器會調(diào)用這些 Hooks,這樣就能夠?qū)⒆远x DOM 邏輯安全地直接插入到組件中。例如,如果想實例化一個圖表庫,可以使用 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});
}
}
每個鉤子都支持一個“相位值”(例如讀取、寫入),Angular 使用這個相位值來合理安排回調(diào)的執(zhí)行時間,從而減少頁面布局的頻繁變化,提高整體性能。
新項目默認(rèn)使用 Vite 和 esbuild
在v16版本中,首次引入了 esbuild 和 Vite 驅(qū)動的構(gòu)建體驗作為開發(fā)預(yù)覽。自此,許多開發(fā)人員進(jìn)行了嘗試,一些企業(yè)合作伙伴反饋稱他們的一些應(yīng)用的構(gòu)建時間縮短了67%!在 v17 中,新應(yīng)用的構(gòu)建器已經(jīng)從開發(fā)預(yù)覽階段正式推出,并默認(rèn)應(yīng)用于所有新應(yīng)用!
此外,在使用混合渲染時,更新了構(gòu)建管道。通過使用SSR和SSG,ng build的構(gòu)建速度提高了87%,ng serve的編輯刷新循環(huán)速度加快了80%。
在未來的次要版本中,將提供原理圖,以使用混合渲染(使用 SSG 或 SSR 進(jìn)行客戶端渲染)自動遷移現(xiàn)有項目。
DevTools 中的依賴注入調(diào)試
去年,Angular 團(tuán)隊展示了 Angular DevTools 中依賴注入調(diào)試功能的預(yù)覽。在過去的幾個月里,實現(xiàn)了全新的調(diào)試 API,能夠插入框架的運(yùn)行時并檢查注入器樹。
基于這些 API,構(gòu)建了一個檢查用戶界面,可以預(yù)覽:
- 組件檢查器中組件的依賴關(guān)系。
- 注入器樹和依賴關(guān)系解析路徑。
- 單個注入器內(nèi)標(biāo)明的供應(yīng)商。