# 了解依赖注入
依赖注入(DI)是 Angular 中的基本概念之一。 DI 被装配进 Angular 框架,并允许带有 Angular 装饰器的类(例如组件、指令、管道和可注入对象)配置它们所需的依赖项。
DI 系统中存在两个主要角色:依赖使用者和依赖提供者。
Angular 使用一种称为 Injector的抽象来促进依赖消费者和依赖提供者之间的互动。当有人请求依赖项时,注入器会检查其注册表以查看那里是否已有可用的实例。如果没有,就会创建一个新实例并将其存储在注册表中。Angular 会在应用的引导过程中创建一个应用范围的注入器(也称为“根”注入器),并会根据需要创建任何其它注入器。在大多数情况下,你都不需要手动创建注入器,但应该知道有这样一个连接提供者和消费者的层次。
本主题介绍了某个类如何作为依赖项的基本场景。Angular 还允许你使用函数、对象、基本类型(例如字符串或 Boolean)或任何其他类型作为依赖项。有关更多信息,请参阅依赖提供者。
# 提供依赖项
假设有一个名为 HeroService 的类需要用作组件中的依赖项。
第一步是添加 @Injectable 装饰器以表明此类可以被注入。
@Injectable()
class HeroService {}
下一步是提供它,以便让其在 DI 中可用。可以在多种地方提供依赖项:
- 在组件级别,使用
@Component
装饰器的providers
字段。在这种情况下,HeroService
将可用于此组件的所有实例以及它的模板中使用的其他组件和指令。例如:
content_copy
@Component({
selector: 'hero-list',
template: '...',
providers: [HeroService]
})
class HeroListComponent {}
当你在组件级别注册提供者时,该组件的每个新实例都会获得一个新的服务实例。
- 在 NgModule 级别,要使用
@NgModule
装饰器的providers
字段。在这种情况下,HeroService
可用于此 NgModule 中声明的所有组件、指令和管道。例如:
content_copy
@NgModule({
declarations: [HeroListComponent]
providers: [HeroService]
})
class HeroListModule {}
当你向特定的 NgModule 注册提供者时,同一个服务实例可用于该 NgModule 中的所有组件。
- 在应用程序根级别,允许将其注入应用程序中的其他类。这可以通过将
providedIn: 'root'
字段添加到@Injectable
装饰器来实现:
content_copy
@Injectable({
providedIn: 'root'
})
class HeroService {}
当你在根级别提供服务时,Angular 会创建一个 HeroService
的共享实例,并将其注入到任何需要它的类中。在 @Injectable
元数据中注册提供者还允许 Angular 通过从已编译的应用程序中删除没用到的服务来优化应用程序,这个过程称为摇树优化(tree-shaking)。
# 注入依赖项
注入依赖项的最常见方法是在类的构造函数中声明它。当 Angular 创建组件、指令或管道类的新实例时,它会通过查看构造函数的参数类型来确定该类需要哪些服务或其他依赖项。例如,如果 HeroListComponent
要用 HeroService
,则构造函数可以如下所示:
content_copy
@Component({ … })
class HeroListComponent {
constructor(private service: HeroService) {}
}
当 Angular 发现一个组件依赖于一项服务时,它会首先检查注入器中是否已有该服务的任何现有实例。如果所请求的服务实例尚不存在,注入器就会使用注册的提供者创建一个,并在将服务返回给 Angular 之前将其添加到注入器中。
当所有请求的服务都已解析并返回时,Angular 就可以用这些服务实例为参数,调用该组件的构造函数。
# 下一步呢?
- 创建和注入服务
- 依赖注入实战