延迟加载可以通过仅加载特定无服务器函数调用所需的模块来帮助减少引导时间。此外,您还可以在无服务器函数热身
后异步加载其他模块,以进一步加快后续调用的引导时间(延迟模块注册)。
如果您熟悉**Angular框架,您可能之前见过[延迟加载模块](https://angular.dev/guide/ngmodules/lazy-loading#lazy-loading-basics)
这个术语。请注意,此技术在 Nest 中功能不同**,因此请将其视为具有类似命名约定的完全不同的功能。
请注意,生命周期钩子方法 不会在延迟加载的模块和服务中调用。
入门
为了按需加载模块,Nest 提供了 LazyModuleLoader
类,可以以正常方式将其注入到类中:
@Injectable()
export class CatsService {
constructor(private lazyModuleLoader: LazyModuleLoader) {}
}
@Injectable()
@Dependencies(LazyModuleLoader)
export class CatsService {
constructor(lazyModuleLoader) {
this.lazyModuleLoader = lazyModuleLoader;
}
}
LazyModuleLoader
类从 @nestjs/core
包导入。
或者,您可以从应用程序引导文件(main.ts
)中获取对 LazyModuleLoader
提供程序的引用,如下所示:
// "app" represents a Nest application instance
const lazyModuleLoader = app.get(LazyModuleLoader)
有了这个,您现在可以使用以下结构加载任何模块:
const { LazyModule } = await import('./lazy.module')
const moduleRef = await this.lazyModuleLoader.load(() => LazyModule)
延迟加载
模块在第一次调用 LazyModuleLoader#load
方法时被缓存。这意味着,每次连续尝试加载 LazyModule
都会非常快,并且会返回一个缓存实例,而不是再次加载模块。
bashLoad "LazyModule" attempt: 1 time: 2.379ms Load "LazyModule" attempt: 2 time: 0.294ms Load "LazyModule" attempt: 3 time: 0.303ms
此外,
延迟加载
模块与应用程序引导程序中急切加载的模块以及应用程序中稍后注册的任何其他延迟模块共享相同的模块图。
其中 lazy.module.ts
是一个 TypeScript 文件,它导出一个 常规 Nest 模块(无需额外更改)。
LazyModuleLoader#load
方法返回 模块引用(LazyModule
的),它允许您浏览内部提供程序列表并使用其注入令牌作为查找键获取对任何提供程序的引用。
例如,假设我们有一个具有以下定义的 LazyModule
:
@Module({
providers: [LazyService],
exports: [LazyService],
})
export class LazyModule {}
延迟加载的模块不能注册为全局模块,因为这根本没有意义(因为它们是延迟注册的,当所有静态注册的模块都已实例化时,按需注册)。同样,注册的全局增强器(保护器/拦截器/等)也无法正常工作。
这样,我们可以获得对LazyService
提供程序的引用,如下所示:
const { LazyModule } = await import('./lazy.module')
const moduleRef = await this.lazyModuleLoader.load(() => LazyModule)
const { LazyService } = await import('./lazy.service')
const lazyService = moduleRef.get(LazyService)
如果您使用Webpack,请确保更新您的tsconfig.json
文件 - 将compilerOptions.module
设置为esnext
并添加compilerOptions.moduleResolution
属性,并将node
作为值:
{
"compilerOptions": {
"module": "esnext",
"moduleResolution": "node"
}
}
设置这些选项后,您将能够利用 代码拆分 功能。
延迟加载控制器、网关和解析器
由于 Nest 中的控制器(或 GraphQL 应用程序中的解析器)代表路由/路径/主题(或查询/变异)的集合,因此您无法使用 LazyModuleLoader
类延迟加载它们。
例如,假设您正在构建一个 REST API(HTTP 应用程序),并在底层使用 Fastify 驱动程序(使用 @nestjs/platform-fastify
包)。在应用程序准备就绪/成功监听消息后,Fastify 不允许您注册路由。这意味着,即使我们分析了模块控制器中注册的路由映射,所有延迟加载的路由也无法访问,因为无法在运行时注册它们。
同样,我们作为 @nestjs/microservices
包的一部分提供的一些传输策略(包括 Kafka、gRPC 或 RabbitMQ)需要在建立连接之前订阅/监听特定主题/频道。一旦您的应用程序开始监听消息,框架将无法订阅/监听新主题。
最后,启用代码优先方法的 @nestjs/graphql
包会根据元数据自动动态生成 GraphQL 模式。这意味着,它需要事先加载所有类。否则,就无法创建适当、有效的模式。
常见用例
最常见的是,当您的工作程序/cron 作业/lambda 和无服务器函数/webhook 必须根据输入参数(路由路径/日期/查询参数等)触发不同的服务(不同的逻辑)时,您会看到延迟加载模块。另一方面,对于启动时间无关紧要的单片应用程序来说,延迟加载模块可能没有太大意义。