高级

分层注入

Nest 的注入是分层的。要理解这处理方法, 首先必须熟悉创建类实例的过程。当任何类依赖于另一个类时, 它将试图在当前范围内查找适当的实例注入。当前范围并不总是类所属的模块。

让我们来考虑一个例子。我们有一个 CoreModule:

core.module.ts

  1. @Module({
  2. imports: [CommonModule],
  3. components: [CoreService, ContextService],
  4. })
  5. export class CoreModule {}

本模块导入 CommonModule 并包含2个组件, 先后是 CoreService 和 ContextService。CommonModule 包含单个组件 CommonService。此组件已导出, 因此在 CoreModule 中也可用。

common.module.ts

  1. @Module({
  2. components: [CommonService],
  3. exports: [CommonService],
  4. })
  5. export class CommonModule {}

现在让我们来看看 ContextService:

core/context.service.ts

  1. @Component()
  2. export class ContextService {
  3. constructor(private readonly commonService: CommonService) {}
  4. }

此类取决于 CommonService。此服务是从子模块 (CommonModule) 导入的, 因此这是一个典型的情况。现在有些令人惊讶的事情, CommonService:

common/common.service.ts

  1. @Component()
  2. export class CommonService {
  3. constructor(private readonly coreService: CoreService) {}
  4. }

CommonService 取决于 CoreService。这是有可能的, 因为 CommonService 实例是在 CoreModule context (由组件注入的, 它属于父模块)。

动机 (Motivation)

这种技术使得使用无限抽象来创建可重用模块成为可能。此外,它允许使用自定义组件功能覆盖导入模块中的每个组件。例如,您可以在特征模块内创建该类的默认实现,但在当前处理的上下文中重载它。

这种技术使得可以使用无穷抽象创建可重用模块。此外, 它还允许使用自定义组件功能覆盖 import 模块中的每个组件。例如, 可以在功能模块内创建类的默认实现, 但在当前处理的 context 中重载它。

!> 这种技术非常强大, 但也非常危险。当你要使用这个功能时要小心, 并确保你完全知道你在做什么。

Mixin 类

TypeScript 2.2 增加了对 ECMAScript 2015 Mixin 类模式的支持。这种模式非常有用,因为将自定义参数传递给某些嵌套应用程序构建块(如拦截器或看守器)并不容易。mixin 类有更多的应用程序, 但在这里, 我们将关注这个单一的用例。

为了演示目的, 让我们重写我们在拦截器部分中构建的 CacheInterceptor, 并提取 isCached 条件。

cache.interceptor.ts

  1. import { Interceptor, NestInterceptor, ExecutionContext } from '@nestjs/common';
  2. import { Observable } from 'rxjs/Observable';
  3. import 'rxjs/add/observable/of';
  4. @Interceptor()
  5. export abstract class CacheInterceptor implements NestInterceptor {
  6. protected abstract readonly isCached: () => boolean;
  7. intercept(dataOrRequest, context: ExecutionContext, stream$: Observable<any>): Observable<any> {
  8. if (this.isCached()) {
  9. return Observable.of([]);
  10. }
  11. return stream$;
  12. }
  13. }

现在, CacheInterceptor 是抽象的, 包含了单个抽象成员-isCached 函数。基于这个类, 我们将创建 mixinCacheInterceptor 函数。

mixin-cache.interceptor.ts

  1. import { mixin } from '@nestjs/common';
  2. import { CacheInterceptor } from './cache.interceptor';
  3. export function mixinCacheInterceptor(isCached: () => boolean) {
  4. return mixin(class extends CacheInterceptor {
  5. protected readonly isCached = isCached;
  6. });
  7. }

!> mixin() 是一个帮助器函数。无论何时创建 mixin 类, 都要使用它。

此函数以 isCached() 谓词作为参数, 并将其赋给 mixin 类。最后一步是设置拦截器:

  1. @UseInterceptors(mixinCacheInterceptor(() => true))
  2. async findAll(): Promise<Cat[]> {
  3. return this.catsService.findAll();
  4. }

mixin() 函数返回类, 所以你可以像使用普通的自创类一样使用它。