Angular9 惰性加載

2020-07-03 14:05 更新

默認情況下,NgModule 都是急性加載的,也就是說它會在應(yīng)用加載時盡快加載,所有模塊都是如此,無論是否立即要用。對于帶有很多路由的大型應(yīng)用,考慮使用惰性加載 —— 一種按需加載 NgModule 的模式。惰性加載可以減小初始包的尺寸,從而減少加載時間。

惰性加載入門

本節(jié)會介紹配置惰性加載路由的基本過程。 想要一個分步的范例,參見本頁的分步設(shè)置部分。

要惰性加載 Angular 模塊,請在 AppRoutingModule routes 中使用 loadchildren 代替 component 進行配置,代碼如下。

  1. //AppRoutingModule (excerpt)
  2. const routes: Routes = [
  3. {
  4. path: 'items',
  5. loadChildren: () => import('./items/items.module').then(m => m.ItemsModule)
  6. }
  7. ];

在惰性加載模塊的路由模塊中,添加一個指向該組件的路由。

  1. //Routing module for lazy loaded module (excerpt)
  2. const routes: Routes = [
  3. {
  4. path: '',
  5. component: ItemsComponent
  6. }
  7. ];

還要確保從 AppModule 中移除了 ItemsModule。

分步設(shè)置

建立惰性加載的特性模塊有兩個主要步驟:

  1. 使用 --route 標志,用 CLI 創(chuàng)建特性模塊。

  1. 配置相關(guān)路由。

建立應(yīng)用

如果你還沒有應(yīng)用,可以遵循下面的步驟使用 CLI 創(chuàng)建一個。如果已經(jīng)有了,可以直接跳到 配置路由部分。 輸入下列命令,其中的 customer-app 表示你的應(yīng)用名稱:

  1. ng new customer-app --routing

這會創(chuàng)建一個名叫 "customer-app" 的應(yīng)用,而 --routing 標識生成了一個名叫 "app-routing.module.ts" 的文件,它是你建立惰性加載的特性模塊時所必須的。 輸入命令 cd customer-app 進入該項目。

注:

  • --routing 選項需要 Angular/CLI 8.1 或更高版本。

創(chuàng)建一個帶路由的特性模塊

接下來,你將需要一個包含路由的目標組件的特性模塊。 要創(chuàng)建它,在終端中輸入如下命令,其中 customers 是特性模塊的名稱。加載 customers 特性模塊的路徑也是 customers,因為它是通過 --route 選項指定的:

  1. ng generate module customers --route customers --module app.module

這將創(chuàng)建一個 "customers" 文件夾,在其 "customers.module.ts" 文件中定義了新的可惰性加載模塊 CustomersModule。該命令會自動在新特性模塊中聲明 CustomersComponent

因為這個新模塊想要惰性加載,所以該命令不會在應(yīng)用的根模塊 "app.module.ts" 中添加對新特性模塊的引用。 相反,它將聲明的路由 customers 添加到以 --module 選項指定的模塊中聲明的 routes 數(shù)組中。

Path:"src/app/app-routing.module.ts" 。

  1. const routes: Routes = [
  2. {
  3. path: 'customers',
  4. loadChildren: () => import('./customers/customers.module').then(m => m.CustomersModule)
  5. }
  6. ];

惰性加載語法使用 loadChildren,其后是一個使用瀏覽器內(nèi)置的 import('...')語法進行動態(tài)導(dǎo)入的函數(shù)。 其導(dǎo)入路徑是到當前模塊的相對路徑。

添加另一個特性模塊

使用同樣的命令創(chuàng)建第二個帶路由的惰性加載特性模塊及其樁組件。

  1. ng generate module orders --route orders --module app.module

這將創(chuàng)建一個名為 "orders" 的新文件夾,其中包含 OrdersModuleOrdersRoutingModule 以及新的 OrdersComponent 源文件。 使用 --route 選項指定的 orders 路由,用惰性加載語法添加到了 "app-routing.module.ts" 文件內(nèi)的 routes 數(shù)組中。

Path:"src/app/app-routing.module.ts" 。

  1. const routes: Routes = [
  2. {
  3. path: 'customers',
  4. loadChildren: () => import('./customers/customers.module').then(m => m.CustomersModule)
  5. },
  6. {
  7. path: 'orders',
  8. loadChildren: () => import('./orders/orders.module').then(m => m.OrdersModule)
  9. }
  10. ];

建立 UI

雖然你也可以在地址欄中輸入 URL,不過導(dǎo)航 UI 會更好用,也更常見。 把 "app.component.html" 中的占位腳本替換成一個自定義的導(dǎo)航,以便你在瀏覽器中能輕松地在模塊之間導(dǎo)航。

Path:"src/app/app.component.html" 。

  1. <h1>
  2. {{title}}
  3. </h1>
  4. <button routerLink="/customers">Customers</button>
  5. <button routerLink="/orders">Orders</button>
  6. <button routerLink="">Home</button>
  7. <router-outlet></router-outlet>

要想在瀏覽器中看到你的應(yīng)用,就在終端窗口中輸入下列命令:

  1. ng serve

然后,跳轉(zhuǎn)到 "localhost:4200",這時你應(yīng)該看到 "customer-app" 和三個按鈕。

這些按鈕生效了,因為 CLI 會自動將特性模塊的路由添加到 "app.module.ts" 中的 routes 數(shù)組中。

導(dǎo)入與路由配置

CLI 會將每個特性模塊自動添加到應(yīng)用級的路由映射表中。 通過添加默認路由來最終完成這些步驟。 在 "app-routing.module.ts" 文件中,使用如下命令更新 routes 數(shù)組:

Path:"src/app/app-routing.module.ts" 。

  1. const routes: Routes = [
  2. {
  3. path: 'customers',
  4. loadChildren: () => import('./customers/customers.module').then(m => m.CustomersModule)
  5. },
  6. {
  7. path: 'orders',
  8. loadChildren: () => import('./orders/orders.module').then(m => m.OrdersModule)
  9. },
  10. {
  11. path: '',
  12. redirectTo: '',
  13. pathMatch: 'full'
  14. }
  15. ];

前兩個路徑是到 CustomersModuleOrdersModule 的路由。 最后一個條目則定義了默認路由??章窂狡ヅ渌胁黄ヅ湎惹奥窂降膬?nèi)容。

特性模塊內(nèi)部

接下來,仔細看看 "customers.module.ts" 文件。如果你使用的是 CLI,并按照此頁面中的步驟進行操作,則無需在此處執(zhí)行任何操作。

Path:"src/app/customers/customers.module.ts" 。

  1. import { NgModule } from '@angular/core';
  2. import { CommonModule } from '@angular/common';
  3. import { CustomersRoutingModule } from './customers-routing.module';
  4. import { CustomersComponent } from './customers.component';
  5. @NgModule({
  6. imports: [
  7. CommonModule,
  8. CustomersRoutingModule
  9. ],
  10. declarations: [CustomersComponent]
  11. })
  12. export class CustomersModule { }

"customers.module.ts" 文件導(dǎo)入了 "customers-routing.module.ts" 和 "customers.component.ts" 文件。@NgModuleimports 數(shù)組中列出了 CustomersRoutingModule,讓 CustomersModule 可以訪問它自己的路由模塊。CustomersComponent 位于 declarations 數(shù)組中,這意味著 CustomersComponent 屬于 CustomersModule。

然后,"app-routing.module.ts" 會使用 JavaScript 的動態(tài)導(dǎo)入功能來導(dǎo)入特性模塊 "customers.module.ts"。

專屬于特性模塊的路由定義文件 "customers-routing.module.ts" 將導(dǎo)入在 "customers.component.ts" 文件中定義的自有特性組件,以及其它 JavaScript 導(dǎo)入語句。然后將空路徑映射到 CustomersComponent。

Path:"src/app/customers/customers-routing.module.ts" 。

  1. import { NgModule } from '@angular/core';
  2. import { Routes, RouterModule } from '@angular/router';
  3. import { CustomersComponent } from './customers.component';
  4. const routes: Routes = [
  5. {
  6. path: '',
  7. component: CustomersComponent
  8. }
  9. ];
  10. @NgModule({
  11. imports: [RouterModule.forChild(routes)],
  12. exports: [RouterModule]
  13. })
  14. export class CustomersRoutingModule { }

這里的 path 設(shè)置為空字符串,因為 AppRoutingModule 中的路徑已經(jīng)設(shè)置為 customers,因此,CustomersRoutingModule 中的此路由已經(jīng)位于 customers 這個上下文中。此路由模塊中的每個路由都是其子路由。

另一個特性模塊中路由模塊的配置也類似。

Path:"src/app/orders/orders-routing.module.ts (excerpt)" 。

  1. import { OrdersComponent } from './orders.component';
  2. const routes: Routes = [
  3. {
  4. path: '',
  5. component: OrdersComponent
  6. }
  7. ];

確認它工作正常

你可以使用 Chrome 開發(fā)者工具來確認一下這些模塊真的是惰性加載的。 在 Chrome 中,按 Cmd+Option+i(Mac)或 Ctrl+Shift+j(PC),并選中 Network 頁標簽。

點擊 OrdersCustomers 按鈕。如果你看到某個 chunk 文件出現(xiàn)了,就表示一切就緒,特性模塊被惰性加載成功了。OrdersCustomers 都應(yīng)該出現(xiàn)一次 chunk,并且它們各自只應(yīng)該出現(xiàn)一次。

要想再次查看它或測試本項目后面的行為,只要點擊 Network 頁左上放的 清除 圖標即可。

然后,使用 Cmd+r(Mac) 或 Ctrl+r(PC) 重新加載頁面。

forRoot() 與 forChild()

你可能已經(jīng)注意到了,CLI 會把 RouterModule.forRoot(routes) 添加到 AppRoutingModuleimports 數(shù)組中。 這會讓 Angular 知道 AppRoutingModule 是一個路由模塊,而 forRoot() 表示這是一個根路由模塊。 它會配置你傳入的所有路由、讓你能訪問路由器指令并注冊 Router。 forRoot() 在應(yīng)用中只應(yīng)該使用一次,也就是這個 AppRoutingModule 中。

CLI 還會把 RouterModule.forChild(routes) 添加到各個特性模塊中。這種方式下 Angular 就會知道這個路由列表只負責提供額外的路由并且其設(shè)計意圖是作為特性模塊使用。你可以在多個模塊中使用 forChild()。

forRoot() 方法為路由器管理全局性的注入器配置。 forChild() 方法中沒有注入器配置,只有像 RouterOutletRouterLink 這樣的指令。 欲知詳情,參見單例服務(wù)章的 forRoot() 模式小節(jié)。

預(yù)加載

預(yù)加載通過在后臺加載部分應(yīng)用來改進用戶體驗。你可以預(yù)加載模塊或組件數(shù)據(jù)。

預(yù)加載模塊

預(yù)加載模塊通過在后臺加載部分應(yīng)用來改善用戶體驗,這樣用戶在激活路由時就無需等待下載這些元素。

要啟用所有惰性加載模塊的預(yù)加載, 請從 Angular 的 router 導(dǎo)入 PreloadAllModules 令牌。

  1. //AppRoutingModule (excerpt)
  2. import { PreloadAllModules } from '@angular/router';

還是在 AppRoutingModule 中,通過 forRoot() 指定你的預(yù)加載策略。

  1. //AppRoutingModule (excerpt)
  2. RouterModule.forRoot(
  3. appRoutes,
  4. {
  5. preloadingStrategy: PreloadAllModules
  6. }
  7. )

預(yù)加載組件數(shù)據(jù)

要預(yù)加載組件數(shù)據(jù),你可以使用 resolver 守衛(wèi)。解析器通過阻止頁面加載來改進用戶體驗,直到顯示頁面時的全部必要數(shù)據(jù)都可用。

創(chuàng)建一個解析器服務(wù)。通過 CLI,生成服務(wù)的命令如下:

  1. ng generate service

在你的服務(wù)中,導(dǎo)入下列路由器成員,實現(xiàn) Resolve 接口,并注入到 Router 服務(wù)中:

  1. //Resolver service (excerpt)
  2. import { Resolve } from '@angular/router';
  3. ...
  4. export class CrisisDetailResolverService implements Resolve<> {
  5. resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<> {
  6. // your logic goes here
  7. }
  8. }

把這個解析器導(dǎo)入此模塊的路由模塊。

  1. //Feature module's routing module (excerpt)
  2. import { YourResolverService } from './your-resolver.service';

在組件的 route 配置中添加一個 resolve 對象。

  1. //Feature module's routing module (excerpt)
  2. {
  3. path: '/your-path',
  4. component: YourComponent,
  5. resolve: {
  6. crisis: YourResolverService
  7. }
  8. }

在此組件中,使用一個 Observable 來從 ActivatedRoute 獲取數(shù)據(jù)。

  1. //Component (excerpt)
  2. ngOnInit() {
  3. this.route.data
  4. .subscribe((your-parameters) => {
  5. // your data-specific code goes here
  6. });
  7. }
  8. ···
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號