Angular 14如何在主页面加载完成后于后台下载所有模块
完全可以实现,Angular 路由原生支持懒加载模块的后台预加载能力,Angular 14 版本不需要引入额外第三方依赖,有三种成熟方案可按需选择:
方案1:内置全量预加载(配置成本最低)
Angular 内置了PreloadAllModules预加载策略,开启后会在主模块加载完成、首屏渲染结束、网络空闲时,自动在后台下载所有loadChildren声明的懒加载模块,不会阻塞首屏交互。
配置方式非常简单,只需要修改根路由模块的forRoot配置即可:
import { NgModule } from '@angular/core'; import { RouterModule, Routes, PreloadAllModules } 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) } ]; @NgModule({ imports: [ RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules // 开启全量预加载 }) ], exports: [RouterModule] }) export class AppRoutingModule { }
这个方案的特点:
- 零额外业务代码,官方实现稳定无兼容问题
- 预加载过程完全在后台进行,用户无感知
- 缺点是控制粒度粗,所有懒加载模块都会被提前下载,无法针对模块、触发时机做定制
方案2:自定义预加载策略(时机与粒度完全可控)
如果需要精确控制预加载的触发时机(比如等首页接口全部返回、核心交互绑定完成后再开始下载),或者只想预加载部分高频访问模块,可以实现自定义预加载策略。
首先写自定义预加载服务:
import { Injectable } from '@angular/core'; import { PreloadingStrategy, Route } from '@angular/router'; import { Observable, of, timer } from 'rxjs'; import { mergeMap } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class AppPreloadStrategy implements PreloadingStrategy { // 预加载开关,主页面加载完成前保持关闭 public canStartPreload = false; preload(route: Route, loadModule: () => Observable<any>): Observable<any> { // 未到预加载时机直接返回,不下载模块 if (!this.canStartPreload) return of(null); // 可在此处加自定义判断:比如根据route.data里的标记决定是否预加载、根据网络环境判断是否预加载 // 加100ms延迟避免抢占主线程资源 return timer(100).pipe(mergeMap(() => loadModule())); } }
在根路由配置里替换预加载策略:
imports: [ RouterModule.forRoot(routes, { preloadingStrategy: AppPreloadStrategy }) ]
最后在主页面加载完成的钩子里打开开关,触发预加载:
import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { AppPreloadStrategy } from './app-preload-strategy.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent implements OnInit { constructor( private router: Router, private preloadStrategy: AppPreloadStrategy ) {} ngOnInit() { // 等页面所有静态资源加载完成 window.addEventListener('load', () => { // 延迟500ms,确保首屏交互不受影响 setTimeout(() => { this.preloadStrategy.canStartPreload = true; // 触发路由预加载检查 this.router.initialNavigation(); }, 500); }); } }
方案3:手动触发模块加载(逻辑最直观)
如果不想依赖路由的预加载机制,可以直接在主页面加载完成后,手动调用动态import拉取模块。ES模块会自动缓存,后续用户导航到对应路由时,Angular会直接使用已加载的模块,不会重复发起请求。
示例代码:
ngAfterViewInit() { // 利用浏览器空闲时间执行,不阻塞主线程 const startLoad = () => { import('./customers/customers.module'); import('./orders/orders.module'); }; if ('requestIdleCallback' in window) { requestIdleCallback(startLoad); } else { // 兼容低版本浏览器 setTimeout(startLoad, 1000); } }
注意:这种方案不需要修改路由的预加载配置,直接在业务逻辑里调用即可,适合需要和业务状态(比如用户登录状态、权限判断)绑定的预加载场景。
补充说明
- 所有预加载行为都不会阻塞用户当前操作,模块下载优先级低于首屏资源和用户交互触发的请求
- 如果项目模块体积极大,不建议全量预加载,可只预加载用户访问概率最高的2-3个模块,避免浪费用户流量
- 以上方案全部兼容Angular 14版本,可直接在项目中使用
内容的提问来源于stack exchange,提问作者Alan Barrientos
相关产品推荐
相关产品推荐

