angular路由中的惰性載入

李明發表於2021-11-20

預設情況下,NgModule 都是急性載入的,也就是說它會在應用載入時儘快載入,所有模組都是如此,無論是否立即要用。對於帶有很多路由的大型應用,考慮使用惰性載入 —— 一種按需載入 NgModule 的模式。惰性載入可以減小初始包的尺寸,從而減少載入時間。

app.modules中:

const routes: Routes = [
  {
    path: 'items',
    loadChildren: () => import('./items/items.module').then(m => m.ItemsModule)
  }
];

loadChildren是路由的一個屬性,該屬性接收一個回撥函式,這使得Angular可以在有需求的時候呼叫這個回撥函式,從而實現了惰性載入。其後是一個使用瀏覽器內建的 import('...') 語法進行動態匯入的函式。 其匯入路徑是到當前模組的相對路徑。

m => m.ItemsModule這也是一個回撥函式。m為引數代表前面import成功的檔案,所以可以使用任意的合法關鍵來替換,比如:f => f.ItemsModule。m.ItemsModule則表示檔案中對應的ItemsModule類。

then()方法是非同步執行,就是當.then()前的方法執行完後再執行then()內部的程式
這樣就避免了,資料沒獲取到等的問題.

此時再仔細看一下loadchildren方法:

LoadChildren函式返回一組要載入的路由。
點開此方法我們發現是這樣定義的

type LoadChildren = LoadChildrenCallback;

LoadChildrenCallback是一個回撥函式,呼叫此函式以解析惰性載入的路由集合。

Angular 會把 RouterModule.forRoot(routes) 新增到 AppRoutingModule 的 imports 陣列中。 這會讓 Angular 知道 AppRoutingModule 是一個路由模組,而 forRoot() 表示這是一個根路由模組。

它會配置你傳入的所有路由、讓你能訪問路由器指令並註冊 Router。 forRoot() 在應用中只應該使用一次,也就是這個 AppRoutingModule 中。

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

forRoot() 方法為路由器管理全域性性的注入器配置。 forChild() 方法中沒有注入器配置,只有像 RouterOutlet 和 RouterLink 這樣的指令。

RouterModule 中提供了 Router 服務,同時還有一些路由指令,比如 RouterOutlet 和 routerLink 等。應用的根模組匯入了 RouterModule,以便應用中有一個 Router 服務,並且讓應用的根元件可以訪問各個路由器指令。任何一個特性模組也必須匯入 RouterModule,這樣它們的元件模板中才能使用這些路由器指令。

如果 RouterModule 沒有 forRoot(),那麼每個特性模組都會例項化一個新的 Router 例項,而這會破壞應用的正常邏輯,因為應用中只能有一個 Router 例項。通過使用 forRoot() 方法,應用的根模組中會匯入 RouterModule.forRoot(...),從而獲得一個 Router 例項,而所有的特性模組要匯入 RouterModule.forChild(...),它就不會例項化另外的 Router。這也是單例模式的一種體現即所有模組共用這一個router例項。

forRoot() 的工作原理

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})

官方對其的註釋為:
建立一個包含所有路由器指令和提供者註冊路由的模組,而不建立新的路由器服務。註冊子模組和延遲載入子模組時,建立 NgModule 如下:

@NgModule({
  imports: [RouterModule.forChild(ROUTES)]
})
class MyNgModule {}

forRoot() 會接受一個服務配置物件,並返回一個 ModuleWithProviders 物件,它帶有下列屬性:

  • ngModule:在這個例子中,就是 NgModule 類。
  • providers - 配置好的服務提供者

forRoot() 方法為路由器管理全域性性的注入器配置。 forChild() 方法中沒有注入器配置,只有像 RouterOutlet 和 RouterLink 這樣的指令。

forChild() 的工作原理

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
static forChild(routes: Routes): ModuleWithProviders<RouterModule>;

forchild會接受配置好的路由資訊,並返回一個 ModuleWithProviders 物件,而這個物件也就是forRoot呼叫時生成的Router例項,而forchild是在這個例項中新增屬於自己的那部分內容。

而這就和前面所說的loadchildren()聯絡在了一起,呼叫loadchildren時系統會在這個router例項中找到forchildren新增的那部分內容,實現按需載入的功能。


最後AppRoutingModule又在exports中宣告瞭RouterModule,這相當於把RouterModule傳送給了AppModule

相關文章