Angular Lazy load学习笔记

简介: Lazy loading, also known as code splitting, lets you divide your JavaScript code into multiple chunks. The result is that you do not have to load all the JavaScript of the full application when a user accesses the first page. Instead, only the chunks that are required for the given page are loaded.

Lazy loading, also known as code splitting, lets you divide your JavaScript code into multiple chunks. The result is that you do not have to load all the JavaScript of the full application when a user accesses the first page. Instead, only the chunks that are required for the given page are loaded.


懒加载可以允许我们将TypeScript编译出的JavaScript代码拆分成若干个chunk, 这样,当应用程序加载时,我们无需将整个应用所需的所有chunk都加载到浏览器中,而是可以实现按需加载的机制,即仅加载那些需要渲染的页面对应的chunk.


我们在Angular项目里执行命令行ng build,即可查看打包出来的chunk名称和对应的大小,如下图所示。


image.png


默认情况下,我们在Angular应用里编写的所有Component,会被ng build打包到一个main chunk里。比如我开发了一个MyCartComponent:


image.png

打包到main chunk后对应的JavaScript代码如下:


image.png


如何让一个Angular应用的Component支持lazy load,即将其和main chunk分开进行打包呢?


看个例子。


在AppRoutingModule里,配置路由信息时,不使用常规的Component属性,而是采用loadChildren,为某个path动态地指定要加载的Component名称:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
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'
  }
];
@NgModule({
  imports: [
    RouterModule.forRoot(routes)
  ],
  exports: [RouterModule],
  providers: []
})
export class AppRoutingModule { }

看看customers.module.ts的实现:

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 { }

里面导入了另一个CustomersRoutingModule:

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 { }

这里才是常规的Angular router定义机制,path和component 字段pair的组合。


执行ng build之后,这次发现main chunk和customers以及orders chunk分别进行打包了,这说明Customers和Orders的lazy loading启用生效了。


image.png

image.png


在运行时能看得更清楚。浏览器里访问应用,因为没有打开customers或者orders页面,因此没有加载对应的chunk:


image.png


点击customers超链接:


image.png


直到此时,才观察到了customers chunk,这就是Angular Component 懒加载模式在运行时的表现效果。


Lazy loading, also known as code splitting, lets you divide your JavaScript code into multiple chunks. The result is that you do not have to load all the JavaScript of the full application when a user accesses the first page. Instead, only the chunks that are required for the given page are loaded. While navigating the storefront, additional chunks are loaded when needed.


code splitting技术发生在application build期间。


Code splitting provided by Angular is typically route-based, which means there is a chunk for the landing page, another chunk for the product page, and so on.


Angular Code split基于路由的,比如landing page分配一个代码chunk,product page分配另一个代码chunk,以此类推。


Since Spartacus is mostly CMS driven, the actual application logic for each route cannot be decided at build time. Business users will eventually alter the page structure by introducing or removing components.


在Spartacus里,每个route的应用逻辑无法在build阶段知晓,因为Spartacus是CMS驱动的,business user可以通过添加或者移除Component的方式来影响页面结构。


image.png

ConfigModule.withConfig({
      cmsComponents: {
        BannerComponent: {
          component: () =>
            import('./lazy/lazy-banner.component').then(
              (m) => m.LazyBanner
            ),
        }
      }
    }),


这个lazy-lazy-banner-component.js.map在哪里?ng build即可看到。


To make code spitting possible, your static JavaScript code (the main app bundle) should not have any static imports to code that you want to lazy load. The builder will notice that the code is already included, and as a result, will not generate a separate chunk for it. This is especially important in the case of importing symbols from libraries.


衡量lazy load的标志就是,builder为code生成单独的chunk.


在 CLI 生成的基本应用中,模块是急性加载的,这意味着它们都是由本应用启动的,Angular 会使用一个依赖注入体系来让一切服务都在模块间有效。对于急性加载式应用,应用中的根注入器会让所有服务提供者都对整个应用有效。


当使用惰性加载时,这种行为需要进行改变。惰性加载就是只有当需要时才加载模块,比如路由中。它们没办法像急性加载模块那样进行加载。这意味着,在它们的 providers 数组中列出的服务都是不可用的,因为根注入器并不知道这些模块。


当 Angular 的路由器惰性加载一个模块时,它会创建一个新的注入器。这个注入器是应用的根注入器的一个子注入器。想象一棵注入器树,它有唯一的根注入器,而每一个惰性加载模块都有一个自己的子注入器。路由器会把根注入器中的所有提供者添加到子注入器中。如果路由器在惰性加载时创建组件,Angular 会更倾向于使用从这些提供者中创建的服务实例,而不是来自应用的根注入器的服务实例。


任何在惰性加载模块的上下文中创建的组件(比如路由导航),都会获取该服务的局部实例,而不是应用的根注入器中的实例。而外部模块中的组件,仍然会收到来自于应用的根注入器创建的实例。


如下图所示:


image.png

image.png

相关文章
|
6月前
|
Web App开发 前端开发 JavaScript
Angular 应用实现 Lazy Load(懒加载)的项目实战经验分享
Angular 应用实现 Lazy Load(懒加载)的项目实战经验分享
51 0
|
7月前
|
设计模式 SQL 关系型数据库
Proxy Facade 在 Angular 应用 Lazy Load 中的作用
Proxy Facade 在 Angular 应用 Lazy Load 中的作用
44 0
|
7月前
|
前端开发 JavaScript UED
Angular 应用 Lazy Loading 设计概述
Angular 应用 Lazy Loading 设计概述
40 0
|
7月前
|
UED
Angular 中的 code splitting 和 lazy loading 技术
Angular 中的 code splitting 和 lazy loading 技术
36 0
|
7月前
|
JavaScript 前端开发 开发者
实现 Angular Lazy loading 时应该避免 Static Imports 的原因
实现 Angular Lazy loading 时应该避免 Static Imports 的原因
22 0
|
7月前
|
UED
Angular 中 Lazy Loading 的陷阱与最佳实践
Angular 中 Lazy Loading 的陷阱与最佳实践
40 0
|
7月前
关于 Angular Lazy loaded modules 中的 providers
关于 Angular Lazy loaded modules 中的 providers
19 0
|
7月前
|
JavaScript 前端开发
如何对 Angular Lazy Loaded Module 进行 Customization
如何对 Angular Lazy Loaded Module 进行 Customization
24 0
|
8月前
|
存储 缓存 JavaScript
Angular Universal 学习笔记
Angular Universal 学习笔记
73 0
|
8月前
|
前端开发 JavaScript API
Angular Change Detection 的学习笔记
Angular Change Detection 的学习笔记
40 0

热门文章

最新文章