延遲載入特性模組
Lazy-loading feature modules
預設情況下,NgModule 都是急性載入的,也就是說它會在應用載入時儘快載入,所有模組都是如此,無論是否立即要用。對於帶有很多路由的大型應用,考慮使用延遲載入 —— 一種按需載入 NgModule 的模式。延遲載入可以減小初始套件的尺寸,從而減少載入時間。
By default, NgModules are eagerly loaded, which means that as soon as the app loads, so do all the NgModules, whether or not they are immediately necessary. For large apps with lots of routes, consider lazy loading—a design pattern that loads NgModules as needed. Lazy loading helps keep initial bundle sizes smaller, which in turn helps decrease load times.
如果需要本頁描述的具有兩個延遲載入模組的範例應用,參閱
For the final sample app with two lazy-loaded modules that this page describes, see the
延遲載入入門
Lazy loading basics
本節會介紹配置延遲載入路由的基本過程。 想要一個分步的範例,參閱本頁的分步設定部分。
This section introduces the basic procedure for configuring a lazy-loaded route. For a step-by-step example, see the step-by-step setup section on this page.
要延遲載入 Angular 模組,請在 AppRoutingModule
routes
中使用 loadchildren
代替 component
進行配置,程式碼如下。
To lazy load Angular modules, use loadchildren
(instead of component
) in your AppRoutingModule
routes
configuration as follows.
const routes: Routes = [
{
path: 'items',
loadChildren: () => import('./items/items.module').then(m => m.ItemsModule)
}
];
在延遲載入模組的路由模組中,新增一個指向該元件的路由。
In the lazy-loaded module's routing module, add a route for the component.
const routes: Routes = [
{
path: '',
component: ItemsComponent
}
];
還要確保從 AppModule
中移除了 ItemsModule
。 想要一個關於延遲載入模組的分步操作指南,請繼續檢視本頁的後續章節。
Also be sure to remove the ItemsModule
from the AppModule
. For step-by-step instructions on lazy loading modules, continue with the following sections of this page.
分步設定
Step-by-step setup
建立延遲載入的特性模組有兩個主要步驟:
There are two main steps to setting up a lazy-loaded feature module:
使用
--route
標誌,用 CLI 建立特性模組。Create the feature module with the CLI, using the
--route
flag.配置相關路由。
Configure the routes.
建立應用
Set up an app
如果你還沒有應用,可以遵循下面的步驟使用 CLI 建立一個。如果已經有了,可以直接跳到 配置路由部分。 輸入下列命令,其中的 customer-app
表示你的應用名稱:
If you don’t already have an app, you can follow the steps below to create one with the CLI. If you already have an app, skip to Configure the routes. Enter the following command where customer-app
is the name of your app:
ng new customer-app --routing
這會建立一個名叫 customer-app
的應用,而 --routing
標識生成了一個名叫 app-routing.module.ts
的檔案,它是你建立延遲載入的特性模組時所必須的。 輸入命令 cd customer-app
進入該專案。
This creates an app called customer-app
and the --routing
flag generates a file called app-routing.module.ts
, which is one of the files you need for setting up lazy loading for your feature module. Navigate into the project by issuing the command cd customer-app
.
--routing
選項需要 Angular/CLI 8.1 或更高版本。 請參閱保持最新。
The --routing
option requires Angular/CLI version 8.1 or higher. See Keeping Up to Date.
建立一個帶路由的特性模組
Create a feature module with routing
接下來,你將需要一個包含路由的目標元件的特性模組。 要建立它,在終端中輸入如下命令,其中 customers
是特性模組的名稱。載入 customers
特性模組的路徑也是 customers
,因為它是透過 --route
選項指定的:
Next, you’ll need a feature module with a component to route to. To make one, enter the following command in the terminal, where customers
is the name of the feature module. The path for loading the customers
feature modules is also customers
because it is specified with the --route
option:
ng generate module customers --route customers --module app.module
這將建立一個 customers
資料夾,在其 customers.module.ts
檔案中定義了新的可延遲載入模組 CustomersModule
。該命令會自動在新特性模組中宣告 CustomersComponent
。
This creates a customers
folder having the new lazy-loadable feature module CustomersModule
defined in the customers.module.ts
file and the routing module CustomersRoutingModule
defined in the customers-routing.module.ts
file. The command automatically declares the CustomersComponent
and imports CustomersRoutingModule
inside the new feature module.
因為這個新模組想要延遲載入,所以該命令不會在應用的根模組 app.module.ts
中新增對新特性模組的參考。 相反,它將宣告的路由 customers
新增到以 --module
選項指定的模組中宣告的 routes
陣列中。
Because the new module is meant to be lazy-loaded, the command does NOT add a reference to the new feature module in the application's root module file, app.module.ts
. Instead, it adds the declared route, customers
to the routes
array declared in the module provided as the --module
option.
const routes: Routes = [
{
path: 'customers',
loadChildren: () => import('./customers/customers.module').then(m => m.CustomersModule)
}
];
注意,延遲載入語法使用 loadChildren
,其後是一個使用瀏覽器內建的 import('...')
語法進行動態匯入的函式。 其匯入路徑是到當前模組的相對路徑。
Notice that the lazy-loading syntax uses loadChildren
followed by a function that uses the browser's built-in import('...')
syntax for dynamic imports. The import path is the relative path to the module.
新增另一個特性模組
Add another feature module
使用同樣的命令建立第二個帶路由的延遲載入特性模組及其樁元件。
Use the same command to create a second lazy-loaded feature module with routing, along with its stub component.
ng generate module orders --route orders --module app.module
這將建立一個名為 orders
的新資料夾,其中包含 OrdersModule
和 OrdersRoutingModule
以及新的 OrdersComponent
原始檔。 使用 --route
選項指定的 orders
路由,用延遲載入語法新增到了 app-routing.module.ts
檔案內的 routes
陣列中。
This creates a new folder called orders
containing the OrdersModule
and OrdersRoutingModule
, along with the new OrdersComponent
source files. The orders
route, specified with the --route
option, is added to the routes
array inside the app-routing.module.ts
file, using the lazy-loading syntax.
const routes: Routes = [
{
path: 'customers',
loadChildren: () => import('./customers/customers.module').then(m => m.CustomersModule)
},
{
path: 'orders',
loadChildren: () => import('./orders/orders.module').then(m => m.OrdersModule)
}
];
建立 UI
Set up the UI
雖然你也可以在位址列中輸入 URL,不過導航 UI 會更好用,也更常見。 把 app.component.html
中的佔位指令碼替換成一個自訂的導航,以便你在瀏覽器中能輕鬆地在模組之間導航。
Though you can type the URL into the address bar, a navigation UI is easier for the user and more common. Replace the default placeholder markup in app.component.html
with a custom nav so you can easily navigate to your modules in the browser:
<h1>
{{title}}
</h1>
<button routerLink="/customers">Customers</button>
<button routerLink="/orders">Orders</button>
<button routerLink="">Home</button>
<router-outlet></router-outlet>
要想在瀏覽器中看到你的應用,就在終端視窗中輸入下列命令:
To see your app in the browser so far, enter the following command in the terminal window:
ng serve
然後,跳轉到 localhost:4200
,這時你應該看到 customer-app
和三個按鈕。
Then go to localhost:4200
where you should see customer-app
and three buttons.

這些按鈕生效了,因為 CLI 會自動將特性模組的路由新增到 app.module.ts
中的 routes
陣列中。
These buttons work, because the CLI automatically added the routes to the feature modules to the routes
array in app.module.ts
.
匯入與路由配置
Imports and route configuration
CLI 會將每個特性模組自動新增到應用級的路由對映表中。 透過新增預設路由來最終完成這些步驟。 在 app-routing.module.ts
檔案中,使用如下命令更新 routes
陣列:
The CLI automatically added each feature module to the routes map at the application level. Finish this off by adding the default route. In the app-routing.module.ts
file, update the routes
array with the following:
const routes: Routes = [
{
path: 'customers',
loadChildren: () => import('./customers/customers.module').then(m => m.CustomersModule)
},
{
path: 'orders',
loadChildren: () => import('./orders/orders.module').then(m => m.OrdersModule)
},
{
path: '',
redirectTo: '',
pathMatch: 'full'
}
];
前兩個路徑是到 CustomersModule
和 OrdersModule
的路由。 最後一個條目則定義了預設路由。空路徑匹配所有不匹配先前路徑的內容。
The first two paths are the routes to the CustomersModule
and the OrdersModule
. The final entry defines a default route. The empty path matches everything that doesn't match an earlier path.
特性模組內部
Inside the feature module
接下來,仔細看看 customers.module.ts
檔案。如果你使用的是 CLI,並按照此頁面中的步驟進行操作,則無需在此處執行任何操作。
Next, take a look at the customers.module.ts
file. If you’re using the CLI and following the steps outlined in this page, you don’t have to do anything here.
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CustomersRoutingModule } from './customers-routing.module';
import { CustomersComponent } from './customers.component';
@NgModule({
imports: [
CommonModule,
CustomersRoutingModule
],
declarations: [CustomersComponent]
})
export class CustomersModule { }
customers.module.ts
檔案匯入了 customers-routing.module.ts
和 customers.component.ts
檔案。@NgModule
的 imports
陣列中列出了 CustomersRoutingModule
,讓 CustomersModule
可以訪問它自己的路由模組。CustomersComponent
位於 declarations
陣列中,這意味著 CustomersComponent
屬於 CustomersModule
。
The customers.module.ts
file imports the customers-routing.module.ts
and customers.component.ts
files. CustomersRoutingModule
is listed in the @NgModule
imports
array giving CustomersModule
access to its own routing module. CustomersComponent
is in the declarations
array, which means CustomersComponent
belongs to the CustomersModule
.
然後,app-routing.module.ts
會使用 JavaScript 的動態匯入功能來匯入特性模組 customers.module.ts
。
The app-routing.module.ts
then imports the feature module, customers.module.ts
using JavaScript's dynamic import.
專屬於特性模組的路由定義檔案 customers-routing.module.ts
將匯入在 customers.component.ts
檔案中定義的自有特性元件,以及其它 JavaScript 匯入語句。然後將空路徑對映到 CustomersComponent
。
The feature-specific route definition file customers-routing.module.ts
imports its own feature component defined in the customers.component.ts
file, along with the other JavaScript import statements. It then maps the empty path to the CustomersComponent
.
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { CustomersComponent } from './customers.component';
const routes: Routes = [
{
path: '',
component: CustomersComponent
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class CustomersRoutingModule { }
這裡的 path
設定為空字串,因為 AppRoutingModule
中的路徑已經設定為 customers
,因此,CustomersRoutingModule
中的此路由已經位於 customers
這個上下文中。此路由模組中的每個路由都是其子路由。
The path
here is set to an empty string because the path in AppRoutingModule
is already set to customers
, so this route in the CustomersRoutingModule
, is already within the customers
context. Every route in this routing module is a child route.
另一個特性模組中路由模組的配置也類似。
The other feature module's routing module is configured similarly.
import { OrdersComponent } from './orders.component';
const routes: Routes = [
{
path: '',
component: OrdersComponent
}
];
確認它工作正常
Verify lazy loading
你可以使用 Chrome 開發者工具來確認一下這些模組真的是延遲載入的。 在 Chrome 中,按 Cmd+Option+i
(Mac)或 Ctrl+Shift+j
(PC),並選中 Network
頁標籤。
You can check to see that a module is indeed being lazy loaded with the Chrome developer tools. In Chrome, open the dev tools by pressing Cmd+Option+i
on a Mac or Ctrl+Shift+j
on a PC and go to the Network Tab.

點選 Orders 或 Customers 按鈕。如果你看到某個 chunk 檔案出現了,就表示一切就緒,特性模組被延遲載入成功了。Orders 和 Customers 都應該出現一次 chunk,並且它們各自只應該出現一次。
Click on the Orders or Customers button. If you see a chunk appear, everything is wired up properly and the feature module is being lazy loaded. A chunk should appear for Orders and for Customers but will only appear once for each.

要想再次檢視它或測試本專案後面的行為,只要點選 Network 頁左上放的 清除
圖示即可。
To see it again, or to test after working in the project, clear everything out by clicking the circle with a line through it in the upper left of the Network Tab:

然後,使用 Cmd+r
(Mac) 或 Ctrl+r
(PC) 重新載入頁面。
Then reload with Cmd+r
or Ctrl+r
, depending on your platform.
forRoot()
與 forChild()
forRoot()
and forChild()
你可能已經注意到了,CLI 會把 RouterModule.forRoot(routes)
新增到 AppRoutingModule
的 imports
陣列中。 這會讓 Angular 知道 AppRoutingModule
是一個路由模組,而 forRoot()
表示這是一個根路由模組。 它會配置你傳入的所有路由、讓你能訪問路由器指令並註冊 Router
。 forRoot()
在應用中只應該使用一次,也就是這個 AppRoutingModule
中。
You might have noticed that the CLI adds RouterModule.forRoot(routes)
to the AppRoutingModule
imports
array. This lets Angular know that the AppRoutingModule
is a routing module and forRoot()
specifies that this is the root routing module. It configures all the routes you pass to it, gives you access to the router directives, and registers the Router
service. Use forRoot()
only once in the application, inside the AppRoutingModule
.
CLI 還會把 RouterModule.forChild(routes)
新增到各個特性模組中。這種方式下 Angular 就會知道這個路由列表只負責提供額外的路由並且其設計意圖是作為特性模組使用。你可以在多個模組中使用 forChild()
。
The CLI also adds RouterModule.forChild(routes)
to feature routing modules. This way, Angular knows that the route list is only responsible for providing additional routes and is intended for feature modules. You can use forChild()
in multiple modules.
forRoot()
方法為路由器管理全域性性的注入器配置。 forChild()
方法中沒有注入器配置,只有像 RouterOutlet
和 RouterLink
這樣的指令。 欲知詳情,參閱單例服務章的 forRoot()
模式小節。
The forRoot()
method takes care of the global injector configuration for the Router. The forChild()
method has no injector configuration. It uses directives such as RouterOutlet
and RouterLink
. For more information, see the forRoot()
pattern section of the Singleton Services guide.
預載入
Preloading
預載入透過在後臺載入部分應用來改進使用者體驗。你可以預載入模組或元件資料。
Preloading improves UX by loading parts of your app in the background. You can preload modules or component data.
預載入模組
Preloading modules
預載入模組透過在後臺載入部分應用來改善使用者體驗,這樣使用者在啟用路由時就無需等待下載這些元素。
Preloading modules improves UX by loading parts of your app in the background so users don't have to wait for the elements to download when they activate a route.
要啟用所有延遲載入模組的預載入, 請從 Angular 的 router
匯入 PreloadAllModules
令牌。
To enable preloading of all lazy loaded modules, import the PreloadAllModules
token from the Angular router
.
import { PreloadAllModules } from '@angular/router';
還是在 AppRoutingModule
中,透過 forRoot()
指定你的預載入策略。
Still in the AppRoutingModule
, specify your preloading strategy in forRoot()
.
RouterModule.forRoot(
appRoutes,
{
preloadingStrategy: PreloadAllModules
}
)
預載入元件資料
Preloading component data
要預載入元件資料,你可以使用 resolver
守衛。解析器透過阻止頁面載入來改進使用者體驗,直到顯示頁面時的全部必要資料都可用。
To preload component data, you can use a resolver
. Resolvers improve UX by blocking the page load until all necessary data is available to fully display the page.
解析器
Resolvers
建立一個解析器服務。透過 CLI,產生服務的命令如下:
Create a resolver service. With the CLI, the command to generate a service is as follows:
ng generate service
在你的服務中,匯入下列路由器成員,實現 Resolve
介面,並注入到 Router
服務中:
In your service, import the following router members, implement Resolve
, and inject the Router
service:
import { Resolve } from '@angular/router';
...
export class CrisisDetailResolverService implements Resolve<> {
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<> {
// your logic goes here
}
}
把這個解析器匯入此模組的路由模組。
Import this resolver into your module's routing module.
import { YourResolverService } from './your-resolver.service';
在元件的 route
配置中新增一個 resolve
物件。
Add a resolve
object to the component's route
configuration.
{
path: '/your-path',
component: YourComponent,
resolve: {
crisis: YourResolverService
}
}
在此元件中,使用一個 Observable
來從 ActivatedRoute
獲取資料。
In the component, use an Observable
to get the data from the ActivatedRoute
.
ngOnInit() {
this.route.data
.subscribe((your-parameters) => {
// your data-specific code goes here
});
}
關於工作範例的更多資訊,請參閱路由課程的預載入部分 。
For more information with a working example, see the routing tutorial section on preloading.
更多關於 NgModule 和路由的知識
More on NgModules and routing
你可能還對下列內容感興趣:
You may also be interested in the following: