freeCodeCamp/guide/russian/angular/dependency-injection/index.md

285 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

---
title: Dependency Injection
localeTitle: Внедрение зависимости
---
# Внедрение зависимости
#### мотивация
Инъекция зависимостей часто более просто называется ДИ. Парадигма существует по всему Угловому. Он сохраняет код гибким, проверяемым и изменяемым. Классы могут наследовать внешнюю логику, не зная, как ее создать. Любые потребители этих классов также не должны знать ничего.
DI спасает классы и потребителей от необходимости знать больше, чем необходимо. Тем не менее, код такой же модульный, как и раньше, благодаря механизмам поддержки DI в Angular.
Услуги являются ключевым благодетелем ДИ. Они полагаются на парадигму для _инъекций_ различным потребителям. Эти потребители могут воспользоваться этим сервисом и / или перенаправить его в другое место.
Служба не одинока. Директивы, трубы, компоненты и т. Д.: Каждая схема в Угловой выгоде от DI так или иначе.
#### Форсунки
Инъекторы представляют собой структуры данных, в которых хранятся инструкции, детализирующие, где и как формируются службы. Они действуют как посредники в системе Angular DI.
Классы модулей, директив и компонентов содержат метаданные, специфичные для инжекторов. Новый экземпляр инжектора сопровождает каждый из этих классов. Таким образом, дерево приложений отражает свою иерархию инжекторов.
`providers: []` метаданные принимают службы, которые затем регистрируются в инжекторе класса. Это поле поставщика добавляет инструкции, необходимые для работы инжектора. Класс (при условии, что он имеет зависимости) создает экземпляр службы, беря на себя класс в качестве своего типа данных. Инжектор выравнивает этот тип. A создает экземпляр этой службы для имени класса.
Разумеется, класс может только указать, для чего инжектор имеет инструкции. Если собственный инжектор класса не имеет зарегистрированной службы, он запрашивает родителя. Так далее и так далее, пока не дойдете до инжектора с помощью сервиса или корня приложения.
Услуги могут регистрироваться у любого инжектора в приложении. Услуги входят в `providers: []` поле метаданных модулей модулей, директив или компонентов. Дети класса могут создавать экземпляр службы, зарегистрированной в инжекторе класса. В конце концов, инъекции инъецированных детей на родительские инжекторы.
#### Внедрение зависимости
Взгляните на скелеты для каждого класса: сервис, модуль, директива и компонент.
```typescript
// service
import { Injectable } from '@angular/core';
@Injectable({
providedIn: /* injector goes here */
})
export class TemplateService {
constructor() { }
}
```
```typescript
// module
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@NgModule({
imports: [
CommonModule
],
declarations: [],
providers: [ /* services go here */ ]
})
export class TemplateModule { }
```
```typescript
// directive
import { Directive } from '@angular/core';
@Directive({
selector: '[appTemplate]',
providers: [ /* services go here */ ]
})
export class TemplateDirective {
constructor() { }
}
```
```typescript
//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 ...
}
```
Каждый скелет может регистрировать услуги инжектора. Фактически, TemplateService _\-_ это сервис. Начиная с Angular 6, службы теперь могут регистрироваться в инжекторах с использованием метаданных `@Injectable` .
##### В любом случае
Обратите внимание на `providedIn: string` ( `@Injectable` ) и `providers: []` ( `@Directive` , `@Componet` и `@Module` ) метаданные. Они сообщают инжекторам, где и как создать сервис. В противном случае инжектора не знали, как создавать экземпляр.
Что делать, если служба имеет зависимости? Куда будут идти результаты? Поставщики отвечают на этот вопрос, так что инжектора могут корректно создавать экземпляры.
Инъекторы образуют основу каркаса DI. Они хранят инструкции для создания служб, которые не нужны потребителям. Они получают экземпляры службы без необходимости знать что-либо об исходной зависимости!
Следует также отметить, что другие схемы без инжекторов все еще могут использовать инъекцию зависимостей. Они не могут регистрировать дополнительные услуги, но они все еще могут быть созданы из инжекторов.
##### обслуживание
`providedIn: string` метаданные `@Injectable` указывают, какой инжектор зарегистрировать. Используя этот метод, и в зависимости от того, будет ли использоваться услуга, служба может или не может зарегистрироваться в инжекторе. Угловые называет это рожание дерева_ .
По умолчанию значение установлено на `'root'` . Это переводится в корневой инжектор приложения. В принципе, установка поля в `'root'` делает сервис доступным в любом месте.
##### Быстрая заметка
Как упоминалось ранее, детские инъекторы отступают от своих родителей. Эта резервная стратегия гарантирует, что родители не должны перерегистрироваться для каждого инжектора. Обратитесь к этой статье « [Услуги и инжекторы»](https://guide.freecodecamp.org/angular/services-and-injectors) для иллюстрации этой концепции.
Зарегистрированные услуги - это _одноточие_ . Смысл, инструкции для создания экземпляра службы существуют только на одном инжекторе. Это предполагает, что он не был явно зарегистрирован в другом месте.
##### Модуль, директива и компонент
Модули и компоненты имеют свой собственный экземпляр инжектора. Это очевидно, учитывая `providers: []` поле метаданных. Это поле принимает множество служб и регистрирует их с помощью инжектора модуля или класса компонента. Этот подход происходит в `@NgModule` , `@Directive` или `@Component` .
Эта стратегия исключает рожание деревьев_ или необязательное удаление неиспользуемых сервисов из инжекторов. Служебные экземпляры живут на своих форсунках в течение всего срока службы модуля или компонента.
#### Создание ссылок
Ссылки на DOM могут быть экземплярами из любого класса. Имейте в виду, что ссылки по-прежнему являются службами. Они отличаются от традиционных сервисов представлением состояния чего-то другого. Эти сервисы включают функции для взаимодействия со своей ссылкой.
Директивы постоянно нуждаются в ссылках DOM. Эти директивы выполняют мутации на своих элементах хоста. См. Следующий пример. Инъектор директивы создает ссылку на главный элемент в конструктор класса.
```typescript
// 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);
}
}
```
```html
// app.component.html
<p [appHighlight]="'yellow'">Highlighted Text!</p>
```
`Renderer2` также получает экземпляр. Какой инжектор выполняет эти услуги? Ну, исходный код каждого сервиса исходит от `@angular/core` . Затем эти службы должны регистрироваться в корневом инжекторе приложения.
```typescript
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 { }
```
Пустой массив поставщиков !? Не бояться. Угловые регистры автоматически регистрируют многие службы с помощью инжектора корня. Это включает `ElementRef` и `Renderer2` . В этом примере мы управляем элементом хоста через его интерфейс, связанный с созданием `ElementRef` . `Renderer2` позволяет нам обновлять модель DOM через Angular.
Вы можете больше узнать о просмотрах из [этой статьи](https://guide.freecodecamp.org/angular/views) . Они являются предпочтительным методом для DOM / просмотра обновлений в Угловых приложениях.
Важно признать роль, которую играют инжекторы в приведенном выше примере. Объявляя типы переменных в конструкторе, класс получает ценные сервисы. Тип данных каждого параметра сопоставляется с набором инструкций внутри инжектора. Если инжектор имеет этот тип, он возвращает экземпляр указанного типа.
#### Создание служб
В статье « [Услуги и инжекторы» подробно](https://guide.freecodecamp.org/angular/services-and-injectors) объясняется этот раздел. Хотя этот раздел повторяет предыдущий раздел или большую часть. Службы часто предоставляют ссылки на что-то еще. Они также могут обеспечить интерфейс, расширяющий возможности класса.
Следующий пример будет определять службу ведения журнала, которая будет добавлена ​​в инжектор компонента через своих `providers: []` метаданные.
```typescript
// 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));
}
}
```
```typescript
// 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();
}
}
```
```html
// 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>
```
Сосредоточьтесь на конструкторе AppComponent и метаданных. Компонент-инжектор получает инструкции из поля метаданных поставщика, содержащего LoggerService. Затем инжектор знает, что создать экземпляр LoggerService из запрошенного в конструкторе.
Параметр конструктора `loggerService` имеет тип `LoggerService` который распознает инжектор. Инжектор следует с помощью экземпляра, как уже упоминалось.
#### Вывод
Инъекция зависимостей (DI) является парадигмой. Способ, которым он работает в Угловом, - это иерархия инжекторов. Класс получает свои ресурсы без необходимости создавать или знать о них. Инъекторы получают инструкцию и создают экземпляр службы в зависимости от того, какой из них был запрошен.
DI показывает много в Угловом. Официальная Угловая документация объясняет, почему парадигма настолько распространена. Они также описывают многочисленные варианты использования для DI по Угловому пути, кроме того, что обсуждалось в этой статье. Проверьте это, нажав ниже!
## источники
* [Угловая команда. «Зависимость от инъекции». _Google_ . Доступ к 1 июня 2018 года](https://angular.io/guide/dependency-injection-pattern)
* [Зуев, Алексей. «Что вы всегда хотели знать о дереве инжекции углового зависимостей». _Угловая глубина_ , 21 марта 2018. Доступ к 1 июня 2018 года](https://blog.angularindepth.com/angular-dependency-injection-and-tree-shakeable-tokens-4588a8f70d5d)
## Ресурсы
* [Угловая документация](https://angular.io/guide/pipes)
* [Угловой репозиторий GitHub](https://github.com/angular/angular)
* [Введение в инъекцию зависимостей](https://angular.io/guide/architecture-services)
* [Расширенная инъекция зависимостей](https://angular.io/guide/dependency-injection-pattern)