angular示例_Angular Dependency Injection用示例解释

angular示例

什么是依赖注入? (What is Dependency Injection?)

动机 (Motivation)

Dependency Injection is often more simply referred to as DI. The paradigm exists throughout Angular. It keeps code flexible, testable, and mutable. Classes can inherit external logic without knowing how to create it. Any consumers of those classes also do not need to know anything.

依赖注入通常更简单地称为DI。 该范例存在于整个Angular中。 它使代码保持灵活,可测试和可变的。 类可以继承外部逻辑而不知道如何创建它。 这些类别的任何消费者也无需了解任何信息。

DI saves classes and consumers alike from having to know more than necessary. Yet the code is as modular as it was before thanks to the mechanisms supporting DI in Angular.

DI可以使类和消费者免于不必要的了解。 然而,由于支持Angular中的DI的机制,代码与以前一样模块化。

Services are a key benefactor of DI. They rely on the paradigm for injection into various consumers. Those consumers can then take advantage of that service provides and/or forward it elsewhere.

服务是DI的关键受益者。 他们依靠这种范式注入各种消费者。 那些消费者然后可以利用该服务提供和/或将其转发到其他地方。

Service are not alone. Directives, pipes, components, and so on: every schematic in Angular benefits from DI in some way or another.

服务并不孤单。 指令,管道,组件等:Angular中的每个原理图都以某种方式受益于DI。

喷油器 (Injectors)

Injectors are data structures that store instructions detailing where and how services form. They act as intermediaries within the Angular DI system.

注入程序是存储指令的数据结构,这些指令详细说明了服务的位置和形成方式。 它们充当Angular DI系统中的中介。

Module, directive, and component classes contain metadata specific to injectors. A new injector instance accompanies every one of these classes. In this way, the application tree mirrors its hierarchy of injectors.

模块,指令和组件类包含特定于注入器的元数据。 这些类别中的每一个都伴随着一个新的喷射器实例。 这样,应用程序树将镜像其注射器的层次结构。

The providers: [] metadata accepts services that then register with the class’ injector. This provider field adds the instructions necessary for an injector to function. A class (assuming it has dependencies) instantiates a service by taking on its class as its data type. The injector aligns this type a creates an instance of that service on the class’ behalf.

providers: []元数据接受服务,然后向类的注入器注册。 该提供者字段添加了注射器工作所需的指令。 一个类(假设它具有依赖性)通过将其类作为其数据类型来实例化服务。 注入器将对齐此类型,并代表类创建该服务的实例。

Of course, the class can only instantiate what the injector has instructions for. If the class’ own injector does not have the service registered, then it queries its parent. So on and so forth until either reaching an injector with the service or the application root.

当然,该类只能实例化注入器的指令。 如果类自己的注入器未注册服务,则它将查询其父级。 依此类推,直到到达具有服务或应用程序根目录的注入器为止。

Services can register at any injector within the application. Services go in the providers: [] metadata field of class modules, directives, or components. The class’ children can instantiate a service registered in the class’ injector. Child injectors fallback on parent injectors after all.

服务可以在应用程序内的任何注入器处注册。 服务位于providers: []类模块,指令或组件的providers: []元数据字段。 班级的孩子可以实例化在班级的注射器中注册的服务。 毕竟,子喷射器在父喷射器上回退。

依赖注入 (Dependency Injection)

Take a look at the skeletons for each class: service, module, directive, and component.

看一下每个类的框架:服务,模块,指令和组件。

// service

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: /* injector goes here */
})
export class TemplateService {
  constructor() { }
}
// module

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

@NgModule({
  imports: [
    CommonModule
  ],
  declarations: [],
  providers: [ /* services go here */ ]
})
export class TemplateModule { }
// directive

import { Directive } from '@angular/core';

@Directive({
  selector: '[appTemplate]',
  providers: [ /* services go here */ ]
})
export class TemplateDirective {
  constructor() { }
}
//component

import { Component } from '@angular/core';

@Component({
  selector: 'app-template',
  templateUrl: './template.component.html',
  styleUrls: ['./template.component.css'],
  providers: [ /* services go here */ ]
})
export class TemplateComponent {
  // class logic ...
}

Each skeleton can register services to an injector. In fact, TemplateService is a service. As of Angular 6, services can now register with injectors using @Injectable metadata.

每个骨架都可以向喷射器注册服务。 实际上,TemplateService 一项服务。 从Angular 6开始,服务现在可以使用@Injectable元数据向注入器注册。

任何状况之下 (In Any Case)

Notice the providedIn: string (@Injectable) and providers: [] (@Directive, @Componet and @Module) metadata. They tell injectors where and how to create a service. Otherwise, injectors would not know how to instantiate.

注意providers: [] providedIn: string ( @Injectable )和providers: [] ( @Directive@Componet @Module@Module )元数据。 他们告诉注入者在哪里以及如何创建服务。 否则,注入器将不知道如何实例化。

What if a service has dependencies? Where would the results go? Providers answers those question so that injectors can instantiate properly.

如果服务具有依赖项怎么办? 结果会去哪里? 提供者回答这些问题,以便注入器可以正确实例化。

Injectors form the backbone of the DI framework. They store instructions to instantiate services so consumers do not have to. They receive service instances without needing to know anything about the source dependency!

注入器构成了DI框架的骨干。 它们存储指令以实例化服务,因此消费者不必这样做。 他们接收服务实例,而无需了解任何有关源依赖的知识!

I should also note that other schematics without injectors can still utilize dependency injection. They cannot register additional services but they can still instantiate from injectors.

我还要注意,其他没有注入器的原理图仍然可以使用依赖注入。 他们无法注册其他服务,但仍可以从注入器实例化。

服务 (Service)

The providedIn: string metadata of @Injectable specifies which injector to register with. Using this method, and depending on if the service gets used, the service may or may not register with the injector. Angular calls this tree-shaking.

@Injectable providedIn: string元数据指定@Injectable哪个注入器注册。 使用此方法,并取决于是否使用服务,该服务可能会或可能不会在注射器中注册。 Angular称此为摇树

By default the value is set to ‘root’. This translates to the root injector of the application. Basically, setting the field to ‘root’ makes the service available anywhere.

默认情况下,该值设置为'root' 。 这将转换为应用程序的根注入器。 基本上,将字段设置为'root'可使服务在任何地方可用。

快速说明 (Quick Note)

As previously mentioned, child injectors fallback on their parents. This fallback strategy ensures parents do not have to re-register for every injector. Refer to this article on Services and Injectors for an illustration of this concept.

如前所述,儿童喷油器退回给父母。 这种后备策略可确保父母不必为每个注射器都重新注册。 有关此概念的说明,请参阅有关服务和注射器的本文。

Registered services are singletons. Meaning, the instructions to instantiate the service exists on only one injector. This assumes it has not been explicitly registered elsewhere.

注册服务为单例 。 意思是,实例化服务的指令仅存在于一个注射器上。 这假定它尚未在其他地方显式注册。

模块,指令和组件 (Module, Directive, and Component)

Modules and components each have their own injector instance. This is evident given the providers: [] metadata field. This field takes an array of services and registers them with the injector of the module or component class. This approach happens in the @NgModule, @Directive, or @Component decorators.

每个模块和组件都有自己的注射器实例。 从providers: []来看这很明显providers: []元数据字段。 该字段采用服务数组,并向模块或组件类的注入器注册它们。 这种方法发生在@NgModule @Directive@Component @Directive@Component装饰器中。

This strategy omits tree-shaking, or the optional removal of unused services from injectors. Service instances live on their injectors for the life of the module or component.

该策略省去了摇树或从注入器中删除未使用服务的可选操作。 服务实例在模块或组件的整个生命周期内都驻留在其注入器上。

实例化引用 (Instantiating References)

References to the DOM can instantiate from any class. Keep in mind that references are still services. They differ from traditional services in representing the state of something else. These services include functions to interact with their reference.

可以从任何类实例化对DOM的引用。 请记住,引用仍然是服务。 它们与传统服务的不同之处在于代表了其他状态。 这些服务包括与参考进行交互的功能。

Directives are in constant need of DOM references. Directives perform mutations on their host elements through these references. See the following example. The directive’s injector instantiates a reference of the host element into the class’ constructor.

指令始终需要DOM引用。 指令通过这些引用在其宿主元素上执行突变。 请参见以下示例。 指令的注入器将宿主元素的引用实例化到类的构造函数中。

// directives/highlight.directive.ts

import { Directive, ElementRef, Renderer2, Input } from '@angular/core';

@Directive({
  selector: '[appHighlight]'
})
export class HighlightDirective {
  constructor(
    private renderer: Renderer2,
    private host: ElementRef
  ) { }

  @Input() set appHighlight (color: string) {
    this.renderer.setStyle(this.host.nativeElement, 'background-color', color);
  }
}
// app.component.html

<p [appHighlight]="'yellow'">Highlighted Text!</p>

Renderer2 also gets instantiated. Which injector do these services come from? Well, each service’s source code comes from @angular/core. These services must then register with the application’s root injector.

Renderer2也被实例化。 这些服务来自哪个喷油嘴? 好吧,每个服务的源代码都来自@angular/core 。 然后,这些服务必须在应用程序的根注入器中注册。

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { HighlightDirective } from './directives/highlight.directive';

@NgModule({
  declarations: [
    AppComponent,
    HighlightDirective
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [
    AppComponent
  ]
})
export class AppModule { }

An empty providers array!? Not to fear. Angular registers many services with the root injector automatically. This includes ElementRef and Renderer2. In this example, we are managing the host element through its interface stemming from the instantiation of ElementRef. Renderer2 lets us update the DOM through Angular’s view model.

空的提供程序数组! 不要害怕。 Angular自动向根注入器注册许多服务。 这包括ElementRefRenderer2 。 在此示例中,我们通过源自ElementRef实例化的接口来管理宿主元素。 Renderer2让我们通过Angular的视图模型更新DOM。

You can read more about views from this article. They are the preferred method for DOM/view updates in Angular applications.

您可以从本文中了解有关视图的更多信息。 它们是Angular应用程序中DOM /视图更新的首选方法。

It is important recognize the role that injectors play in the above example. By declaring variable types in the constructor, the class obtains valuable services. Each parameter’s data type maps to a set of instructions within the injector. If the injector has that type, it returns an instance of said type.

重要的是要认识到喷射器在以上示例中所扮演的角色。 通过在构造函数中声明变量类型,该类可以获得有价值的服务。 每个参数的数据类型都映射到注射器内的一组指令。 如果注入器具有该类型,则返回该类型的实例。

实例化服务 (Instantiating Services)

The Services and Injectors article explains this section to an extent. Though, this section rehashes the previous section or the most part. Services will often provide references to something else. They may just as well provide an interface extending a class’ capabilities.

服务和喷射器文章在一定程度上解释了此部分。 但是,本节将重整上一节或大部分内容。 服务通常会提供对其他内容的引用。 它们也可能提供扩展类功能的接口。

The next example will define a logging service that gets added to a component’s injector via its providers: [] metadata.

下一个示例将定义一个日志记录服务,该服务通过其providers: []添加到组件的注入器providers: []元数据。

// services/logger.service.ts

import { Injectable } from '@angular/core';

@Injectable()
export class LoggerService {
  callStack: string[] = [];

  addLog(message: string): void {
    this.callStack = [message].concat(this.callStack);
    this.printHead();
  }

  clear(): void {
    this.printLog();
    this.callStack = [];
    console.log(“DELETED LOG”);
  }

  private printHead(): void {
    console.log(this.callStack[0] || null);
  }

  private printLog(): void {
    this.callStack.reverse().forEach((log) => console.log(message));
  }
}
// app.component.ts

import { Component } from '@angular/core';
import { LoggerService } from './services/logger.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  providers: [LoggerService]
})
export class AppComponent {
  constructor(private logger: LoggerService) { }

  logMessage(event: any, message: string): void {
    event.preventDefault();
    this.logger.addLog(`Message: ${message}`);
  }

  clearLog(): void {
    this.logger.clear();
  }
}
// app.component.html

<h1>Log Example</h1>
<form (submit)="logMessage($event, userInput.value)">
  <input #userInput placeholder="Type a message...">
  <button type="submit">SUBMIT</button>
</form>

<h3>Delete Logged Messages</h3>
<button type="button" (click)="clearLog()">CLEAR</button>

Focus on the AppComponent constructor and metadata. The component injector receives instructions from the provider’s metadata field containing LoggerService. The injector then knows what to instantiate LoggerService from requested in the constructor.

专注于AppComponent构造函数和元数据。 组件注入器从包含LoggerService的提供程序的元数据字段接收指令。 然后,注入器知道从构造函数中请求实例化LoggerService的方式。

The constructor parameter loggerService has the type LoggerService which the injector recognizes. The injector follows through with the instantiation as mentioned.

构造函数参数loggerService具有注入器可识别的LoggerService类型。 注入程序执行上述实例化。

结论 (Conclusion)

Dependency injection (DI) is a paradigm. The way it works in Angular is through a hierarchy of injectors. A class receives its resources without having to create or know about them. Injectors receive instruction and instantiate a service depending on which one was requested.

依赖注入(DI)是一种范例。 它在Angular中的工作方式是通过注射器的层次结构。 类无需创建或了解资源就可以获取其资源。 注入器接收指令并根据所请求的服务实例化服务。

DI shows up a lot in Angular. The official Angular documentation explains why the paradigm is so prevalent. They also go on to describe the numerous use-cases for DI in Angular way beyond what was discussed in this article. Check it out by clicking below!

DI在Angular中显示很多。 Angular官方文档解释了为什么这种范式如此普遍。 除了本文讨论的内容外,他们还以Angular方式描述了DI的众多用例。 点击下面查看!

有关依赖项注入的更多信息: (More on dependency injection:)

翻译自: https://www.freecodecamp.org/news/angular-dependency-injection/

angular示例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值