在 Angular2 组件配置providers
中是我们可以指定的键之一。这些提供者是如何定义的,它们的用途是什么?
@Component({
..
providers: [..],
..
})
注意:
Angular2 文档正在逐渐成熟,但仍然很少。它目前将提供者定义为:
组件所需服务的一组依赖注入提供程序。
这个递归定义不是很有帮助。通过示例进行更详细的解释确实会有所帮助。
在 Angular2 组件配置providers
中是我们可以指定的键之一。这些提供者是如何定义的,它们的用途是什么?
@Component({
..
providers: [..],
..
})
注意:
Angular2 文档正在逐渐成熟,但仍然很少。它目前将提供者定义为:
组件所需服务的一组依赖注入提供程序。
这个递归定义不是很有帮助。通过示例进行更详细的解释确实会有所帮助。
提供者通常是单例(一个实例)对象,其他对象可以通过依赖注入 (DI) 访问。
如果您计划多次使用一个对象,例如,Http
不同组件中的服务,您可以请求该服务的相同实例(重用它)。通过提供对 DI 为您创建的同一对象的引用,您可以在 DI 的帮助下做到这一点。
@Component){
..
providers: [Http]
}
..而不是每次都创建新对象:
@Component){}
class Cmp {
constructor() {
// this is pseudo code, doens't work
this.http = new Http(...options);
}
}
这是一个近似值,但这是依赖注入背后的一般思想- 让框架处理可重用对象的创建和维护......提供者是 Angular 对这些可重用对象(依赖项)的术语。
注册注射剂
提供者让 Angular 的 DI 知道可注入对象,并定义可注入对象(服务)的范围。
注射器的层次结构
Angular 的 DI 创建了一个类似于组件和指令结构的注入器树(父 > 子 > 孙 >...)。
每个提供者单个实例
每个注入器都维护提供程序。每个提供者都提供一个可注入的实例。
提供者查找
当组件或指令具有依赖项(构造函数参数)时,DI 开始在此组件的注入器中查找提供程序。如果它有一个,它会从这个提供者请求实例并注入它。
如果注入器没有请求的键(类型)的提供者,则访问父注入器,直到根(引导程序),直到找到提供者并且可以注入其实例。(如果未找到提供程序,则 DI 会引发错误)。
定义可注入实例的范围
通过这种方式,您可以定义共享服务的范围,因为 DI 从请求实例的组件开始向上查找,直到找到一个。
单身与否
您提供了多少个可注入的位置决定了将创建多少个实例(它们仅在实际请求时才被实例化)。
如果您想要整个应用程序的单个实例,则仅在根组件处提供一次可注入(或导致bootstrap(AppComponent, [...])
相同行为)。
如果您想为每个组件创建一个新实例A
,请将其添加到组件的提供者中A
。
(更新) NgModule 懒惰和非懒惰
随着NgModule
模块的引入,引入了额外的级别。使用非延迟加载模块注册的提供程序位于层次结构中的根组件之上。
延迟加载的模块位于这些组件加载的组件和指令之上。
因为提供程序在创建注入器后是只读的,所以无法将延迟加载模块中的提供程序添加到根注入器。因此,延迟加载的模块有自己的根范围。
将提供者想象成一个告诉 Angular 如何注入服务的配方。
我们经常以这种方式声明提供者:
providers: [AnyService]
这只是一个简写:
[new Provider(AnyService, {useClass: AnyService})]
两种方法都在说:每当有人需要“AnyService”时,提供“AnyService”类
看到即使我在上面的示例中提供相同的类,在另一种情况下我也可以做这样的事情。
[new Provider(AnyService, {useClass: AnyServiceCustom})]
但在这两种情况下,构造函数都将保持不变:
constructor( private _anyService: AnyService) {
}
为了更好地理解它,您需要了解依赖注入在 Angular 2 中是如何工作的,因为提供程序与它直接相关。
这是每个 Angular 2 开发人员的必读之书。
添加@Sasxa 的话,我想指出Adam Freeman 的Pro Angular 书(第20 章(使用服务提供者)),以获得更好、更清晰、更详细的解释以及令人惊叹的示例。
提供者是Angular 第一次需要解析依赖时创建和管理服务对象的类。Providers用于将类注册到 Angular 模块中作为服务。然后,该服务类可以在模块中的自身创建阶段被其他组件使用。
“服务是提供通用功能以支持应用程序中的其他构建块的对象,例如指令、组件和管道。服务的重要之处在于它们的使用方式,即通过称为依赖注入的过程。使用服务可以增加 Angular 应用程序的灵活性和可扩展性,但依赖注入可能是一个难以理解的话题。” (专业角度(第 20 章))
实际上,服务可以通过依赖注入设法将对象分发为服务。
import { Injectable } from "@angular/core";
export enum LogLevel {DEBUG, INFO, ERROR}
@Injectable()
export class LogService {
minimumLevel: LogLevel = LogLevel.INFO;
logInfoMessage(message: string){
this.logMessage(LogLevel.INFO, message);
}
}
@Component({
selector: "example",
templateUrl: "example.component.html"
})
export class exampleComponent {
constructor(logService: LogService) {};
//to do impl
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@NgModule({
imports: [ BrowserModule ],
providers: [ LogService ],
declarations: [ ExampleComponent],
bootstrap: [ AppComponent ]
})
export class AppModule { }
提供者只是服务的实例。
您可以创建一次并在任何地方使用它们,也可以创建多个实例。
让我们了解如何在 Angular 中使用它们
所有的服务都在 Angular 中注册,但是在我们实例化它们之前它们不能被使用。所以首先,我们必须实例化服务,我们通过使用提供者来做到这一点。
有两种方法可以实例化服务。首先使用providers 数组,第二个是使用providedIn。
第一种方法使用Providers Array
要在全球范围内使用该服务,我们可以将提供程序放在 AppModule 中。通过这样做,该服务的实例被创建并且应用程序中的所有组件或其他服务将使用相同的实例。
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { NewService } from './newService';
@NgModule({
declarations: [
AppComponent
],
providers: [NewService],
bootstrap: [AppComponent]
})
export class AppModule { }
要在任何特定组件中使用服务,我们可以将提供程序放在 ComponentModule 中。通过这样做,该服务的新实例被创建并且所有子组件将使用相同的实例(它将覆盖父实例)。
import { Component, OnInit } from '@angular/core';
import { NewService } from './newService';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
providers:[NewService]
})
export class AppComponent implements OnInit {
constructor(private newService: newService) { }
ngOnInit() { }
}
注意:如果您将提供程序放在 AppComponent 中,则该应用程序中的所有组件都可以使用该实例,但其他服务将无权访问该实例。要使其他服务也使用相同的实例,请将其放在 AppModule 中。
第二种方法使用providedIn
您可以使用 Injectable 装饰器来实例化任何服务。
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root' | Type<any>
})
export class UserService {
}
如果它是 root,那么整个应用程序都可以访问该服务。这意味着 Angular 创建了该服务的单个实例,而整个应用程序使用相同的实例。
如果只能在特定模块中访问它,我们可以通过为提供的模块提供模块名称来做到这一点
@Injectable({
providedIn: AnyModule
})
使用 Injectable 装饰器实例化服务的另一个优点是,如果该服务根本没有在该应用程序的任何地方使用,那么它不会在编译的 Angular 应用程序中存在。
import { service_name} from '../path';
@Component({
selector: 'selector_name',
templateUrl: './html file name ',
styleUrls: ['./css file name '],
providers: [ ./'service_name'];
})
export class AppComponent {
constructor(private Service_name: service_name) {
//enter code here
}