## 循环依赖
当两个类互相依赖时就会出现循环依赖. 例如,当 `A` 类需要 `B` 类,而 `B` 类也需要 `A` 类时,就会产生**循环依赖**。`Nest` 允许在提供者( `provider` )和模块( `module` )之间创建循环依赖关系.
建议尽可能避免循环依赖。但是有时候难以避免,Nest提供了两个方法来解决这个问题.本章中我们提供了两种技术,即`正向引用(forward reference)`和`模块引用(ModuleRef)`来从注入容器中获取一个提供者。
我们也讨论了在模块间处理循环依赖的问题。
> 循环依赖也可以使用`封装桶文件/index.ts`文件成组导入。桶(Barrel)文件应该从模块/类中省略掉。例如,当在同一个目录下作为桶文件导入时不应使用桶文件,例如,cats/cats.controller不应该导入cat到cats/cats.service文件。更多内容参见[github issue](https://github.com/nestjs/nest/issues/1181#issuecomment-430197191)
### 前向引用
**前向引用**允许 `Nest` 引用目前尚未被定义的引用。当`CatsService` 和 `CommonService` 相互依赖时,关系的双方都需要使用 `@Inject()` 和 `forwardRef()` ,否则 `Nest` 不会实例化它们,因为所有基本元数据都不可用。让我们看看下面的代码片段:
> cats.service.ts
```typescript
@Injectable()
export class CatsService {
constructor(
@Inject(forwardRef(() => CommonService))
private readonly commonService: CommonService,
) {}
}
```
> `forwardRef()` 需要从 `@nestjs/common` 包中导入的。
这只是关系的一方面。现在让我们对 `CommonService` 做同样的事情:
> common.service.ts
```typescript
@Injectable()
export class CommonService {
constructor(
@Inject(forwardRef(() => CatsService))
private readonly catsService: CatsService,
) {}
}
```
!> 实例化的顺序是不确定的。确保您的代码不依赖于首先调用哪个构造函数。具有循环依赖依赖于提供者`Scope.REQUEST`可能会导致未定义的依赖。更多信息[在这里](https://github.com/nestjs/nest/issues/5778)
### 可选的模块引用(`ModuleRef`)类
一个选择是使用`forwardRef()`来重构你的代码,并使用`ModuleRef`类来在循环引用关系一侧获取提供者。更多关于`ModuleRef`类的内容参考[这里](https://docs.nestjs.com/fundamentals/module-ref)。
### 模块前向引用
为了处理模块( `module` )之间的循环依赖,必须在模块关联的两个部分上使用相同的 `forwardRef()`:
> common.module.ts
```typescript
@Module({
imports: [forwardRef(() => CatsModule)],
})
export class CommonModule {}
```
- 介绍
- 概述
- 第一步
- 控制器
- 提供者
- 模块
- 中间件
- 异常过滤器
- 管道
- 守卫
- 拦截器
- 自定义装饰器
- 基础知识
- 自定义提供者
- 异步提供者
- 动态模块
- 注入作用域
- 循环依赖
- 模块参考
- 懒加载模块
- 应用上下文
- 生命周期事件
- 跨平台
- 测试
- 技术
- 数据库
- Mongo
- 配置
- 验证
- 缓存
- 序列化
- 版本控制
- 定时任务
- 队列
- 日志
- Cookies
- 事件
- 压缩
- 文件上传
- 流式处理文件
- HTTP模块
- Session(会话)
- MVC
- 性能(Fastify)
- 服务器端事件发送
- 安全
- 认证(Authentication)
- 授权(Authorization)
- 加密和散列
- Helmet
- CORS(跨域请求)
- CSRF保护
- 限速
- GraphQL
- 快速开始
- 解析器(resolvers)
- 变更(Mutations)
- 订阅(Subscriptions)
- 标量(Scalars)
- 指令(directives)
- 接口(Interfaces)
- 联合类型
- 枚举(Enums)
- 字段中间件
- 映射类型
- 插件
- 复杂性
- 扩展
- CLI插件
- 生成SDL
- 其他功能
- 联合服务
- 迁移指南
- Websocket
- 网关
- 异常过滤器
- 管道
- 守卫
- 拦截器
- 适配器
- 微服务
- 概述
- Redis
- MQTT
- NATS
- RabbitMQ
- Kafka
- gRPC
- 自定义传输器
- 异常过滤器
- 管道
- 守卫
- 拦截器
- 独立应用
- Cli
- 概述
- 工作空间
- 库
- 用法
- 脚本
- Openapi
- 介绍
- 类型和参数
- 操作
- 安全
- 映射类型
- 装饰器
- CLI插件
- 其他特性
- 迁移指南
- 秘籍
- CRUD 生成器
- 热重载
- MikroORM
- TypeORM
- Mongoose
- 序列化
- 路由模块
- Swagger
- 健康检查
- CQRS
- 文档
- Prisma
- 静态服务
- Nest Commander
- 问答
- Serverless
- HTTP 适配器
- 全局路由前缀
- 混合应用
- HTTPS 和多服务器
- 请求生命周期
- 常见错误
- 实例
- 迁移指南
- 发现
- 谁在使用Nest?