- 異步路由的預加載示例: 為了盡可能減小初始加載體積和最快的加載速度,讓 主模塊和A模塊 先加載;如何懶加載其他模塊,但是B 模塊可能是 用戶在打開應用后,幾分鍾或幾秒鍾就會訪問的模塊;(比如打開微信后,是不是進入主頁面;然后是不是要打開朋友圈瞅瞅;而B模塊就相當於朋友圈功能;)所以,這個時候在用戶打開B模塊前;該模塊就已經預加載完畢可供訪問;
- 預加載原理:
- 每次成功導航后,路由器會在自己的配置中查找尚未加載並且可以預加載的模塊
- 預加載策略:
- 默認 都不預加載,懶加載的模塊仍會按需加載
- 預加載所有懶加載模塊
- 自定義預加載
- 用戶場景:將CrisisCenterModule 改為默認懶加載,並使用全部預加載策略來加載所有懶加載模塊
- 對crisis-center 模塊進行懶加載處理
// crisis-center-routing.ts 該路徑為空路徑 const crisisCenterRoutes: Routes = [ { path: '', component: CrisisCenterComponent, children: [ { path: '', component: CrisisListComponent, children: [ // tslint:disable-next-line: max-line-length { path: ':id', component: CrisisDetailComponent, canDeactivate: [CanDeactivateGuard], resolve: { crisis: CrisisDetailResolverService }}, { path: '', component: CrisisCenterHomeComponent} ]} ] } ]; // AppRoutingModule 增加該模塊路由,並設置loadChildren const appRoutes: Routes = [ { path: 'compose', component: ComposeMessageComponent, outlet: 'popup' }, { path: 'admin', loadChildren: () => import('./admin/admin.module').then(mod => mod.AdminModule), canLoad: [AuthGuard] }, { path: 'crisis-center', loadChildren: () => import('./crisis-center/crisis-center.module').then(mod => mod.CrisisCenterModule), data: { preload: true } // 自定義預加載 }, { path: '', redirectTo: '/superheroes', pathMatch: 'full' }, { path: '**', component: PageNotFoundComponent } ]; // AppModule 中 移除該模塊 import { HeroesModule } from './heroes/heroes.module'; // import { CrisisCenterModule } from './crisis-center/crisis-center.module'; // import { AdminModule} from './admin/admin.module'; import { AuthModule} from './auth/auth.module'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; // 導入動畫模塊 import { PageNotFoundComponent } from './page-not-found/page-not-found.component'; import { ComposeMessageComponent } from './compose-message/compose-message.component'; @NgModule({ declarations: [ AppComponent, PageNotFoundComponent, ComposeMessageComponent ], imports: [ BrowserModule, FormsModule, HeroesModule, // CrisisCenterModule, // AdminModule, AuthModule, AppRoutingModule, BrowserAnimationsModule ],
- 為所有懶加載模塊啟動預加載功能,在AppRoutingModule 中導入PreloadAllModules
import { NgModule } from '@angular/core'; import { RouterModule, Routes, PreloadAllModules } from '@angular/router'; import { ComposeMessageComponent } from './compose-message/compose-message.component'; import { PageNotFoundComponent } from './page-not-found/page-not-found.component'; import { AuthGuard } from './auth/auth.guard'; const appRoutes: Routes = [ { path: 'compose', component: ComposeMessageComponent, outlet: 'popup' }, { path: 'admin', loadChildren: () => import('./admin/admin.module').then(mod => mod.AdminModule), canLoad: [AuthGuard] //CanLoad 會阻塞預加載,該優先級高於預加載策略 }, { path: 'crisis-center', loadChildren: () => import('./crisis-center/crisis-center.module').then(mod => mod.CrisisCenterModule), data: { preload: true } }, { path: '', redirectTo: '/superheroes', pathMatch: 'full' }, { path: '**', component: PageNotFoundComponent } ]; @NgModule({ imports: [ RouterModule.forRoot( appRoutes, { enableTracing: false, preloadingStrategy: PreloadAllModules, //讓所有(帶loadChildren屬性的路由)懶加載模塊立即預加載 } ) ], exports: [ RouterModule ] }) export class AppRoutingModule { }
- 關於自定義預加載;這里自定義策略為:只預加載data.preload 為 true 的路由;
- 生成自定義服務
ng generate service selective-preloading-strategy import { Injectable } from '@angular/core'; import { PreloadingStrategy, Route } from '@angular/router'; import { Observable, of } from 'rxjs'; @Injectable({ providedIn: 'root', }) export class SelectivePreloadingStrategyService implements PreloadingStrategy { preloadedModules: string[] = []; // 參數 route -- 要加載的路由 load() -- 加載器函數,異步加載帶路由的模塊 // 如果該路由應該預加載,就會跳用load()函數返回Observable對象,否則返回null; preload(route: Route, load: () => Observable<any>): Observable<any> { if (route.data && route.data['preload']) { this.preloadedModules.push(route.path); //會將所選路由記錄在數組中; console.log('Preloaded: ' + route.path); return load(); } else { return of(null); } } }
- 自定義預加載處理
// AppRoutingModule import { NgModule } from '@angular/core'; import { RouterModule, Routes, PreloadAllModules } from '@angular/router'; import { ComposeMessageComponent } from './compose-message/compose-message.component'; import { PageNotFoundComponent } from './page-not-found/page-not-found.component'; import { AuthGuard } from './auth/auth.guard'; import { SelectivePreloadingStrategyService } from './selective-preloading-strategy.service'; const appRoutes: Routes = [ { path: 'compose', component: ComposeMessageComponent, outlet: 'popup' }, { path: 'admin', loadChildren: () => import('./admin/admin.module').then(mod => mod.AdminModule), canLoad: [AuthGuard] }, { path: 'crisis-center', loadChildren: () => import('./crisis-center/crisis-center.module').then(mod => mod.CrisisCenterModule), data: { preload: true } }, { path: '', redirectTo: '/superheroes', pathMatch: 'full' }, { path: '**', component: PageNotFoundComponent } ]; @NgModule({ imports: [ RouterModule.forRoot( appRoutes, { enableTracing: false, preloadingStrategy: SelectivePreloadingStrategyService, } ) ], exports: [ RouterModule ] }) export class AppRoutingModule { }
- 編輯adminDashboardComponent 來顯示預加載路由日志, 當加載完初始路由后,crisisCenterModule被預加載,通過該模塊可以在控制台看到日志
// html <p>Dashboard</p> <p>Session ID: {{ sessionId | async }}</p> <a id="anchor"></a> <p>Token: {{ token | async }}</p> Preloaded Modules <ul> <li *ngFor="let module of modules">{{ module }}</li> </ul> // ts import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { SelectivePreloadingStrategyService } from '../../selective-preloading-strategy.service'; @Component({ selector: 'app-admin-dashboard', templateUrl: './admin-dashboard.component.html', styleUrls: ['./admin-dashboard.component.css'] }) export class AdminDashboardComponent implements OnInit { sessionId: Observable<string>; token: Observable<string>; modules: string[]; constructor( private route: ActivatedRoute, preloadStrategy: SelectivePreloadingStrategyService ) { this.modules = preloadStrategy.preloadedModules; } ngOnInit() { this.sessionId = this.route .queryParamMap .pipe(map(params => params.get('session_id') || 'None')); this.token = this.route .fragment .pipe(map(fragment => fragment || 'None')); } }