Русский
Русский
English
Статистика
Реклама

Что можно положить в механизм Dependency Injection в Angular?

Почти каждый разработчик на Angular может найти в Dependency Injection решение своей проблемы. Это хорошо было видно в комментариях к моей прошлой статье. Люди рассматривали различные варианты работы с данными из DI, сравнивали их удобство для той или иной ситуации. Это здорово, потому что такой простой инструмент дает нам столько возможностей.

Но несколько человек отписались мне, что им тяжело понять DI и его возможности в Angular. В интернете не так уж много материалов о том, как использовать DI эффективно, и для многих разработчиков он сводится к работе с глобальными сервисами или передачей глобальных данных из корня приложения в компоненты.

Давайте посмотрим на этот механизм в Angular чуть глубже.




Знаете ли вы свои зависимости?


Иногда нелегко понять, сколько зависимостей имеет ваш код.

Например, взгляните на этот псевдокласс и посчитайте, сколько зависимостей он имеет:

import { API_URL } from '../../../env/api-url';import { Logger } from '../../services/logger'; class PseudoClass {   request() {       fetch(API_URL).then(...);   }    onError(error) {       const logger = new Logger();        logger.log(document.location, error);   }}

Ответ
fetch браузерное API, опираемся на глобальную переменную, ожидая, что она объявлена.

API_URL импортированные данные из другого файла тоже можно считать зависимостью вашего класса (зависимость от расположения файла).

new Logger() также импортированные данные из другого файла и пересоздания множества экземпляров класса, когда нам достаточно лишь одного.

document также браузерное API и завязка на глобальную переменную.


Ну и что же не так?


Например, такой класс тяжело протестировать, так как он зависит от импортированных данных из других файлов и конкретных сущностей в них.

Другая ситуация: document и fetch будут без проблем работать в вашем браузере. Но если однажды вам потребуется перенести приложение в Server Side Rendering, то в nodejs окружении необходимых глобальных переменных может не быть.

Так и что же за DI и зачем он нужен?


Механизм внедрения зависимостей управляет зависимостями внутри приложения. В принципе, для нас, как для Angular-разработчиков, эта система довольно простая. Есть две основные операции: положить что-то в дерево зависимостей или получить что-то из него.

Механизм внедрения зависимостей управляет зависимостями внутри приложения. В принципе, для нас, как для Angular-разработчиков, эта система довольно простая. Есть две основные операции: положить что-то в дерево зависимостей или получить что-то из него.

Если хотите рассмотреть DI с более теоретической стороны, почитайте о принципе инверсии управления. Также можете посмотреть интересные видеоматериалы по теме: серия видео про IoC и DI у Ильи Климова на русском или небольшое видео про IoC на английском.

Вся магия возникает от порядка, в котором мы поставляем и берем зависимости.

Схема работы областей видимости в DI:


Что мы можем положить в DI?


Первая из операций с DI что-то положить в него. Собственно, для этого Angular позволяет нам прописывать providers-массив в декораторах наших модулей, компонентов или директив. Давайте посмотрим, из чего этот массив может состоять.

Providing класса


Обычно это знает каждый разработчик на Angular. Это тот случай, когда вы добавляете в приложение сервис.

Angular создает экземпляр класса, когда вы запрашиваете его в первый раз. А с Angular 6 мы можем и вовсе не прописывать классы в массив providers, а указать самому классу, в какое место в DI ему встать с providedIn:

providers: [   {       provide: SomeService,       useClass: SomeService   },   // Angular позволяет сократить эту запись как самый частый кейс:   SomeService]


Providing значения


Также через DI можно поставлять константные значения. Это может быть как простая строка с URL вашего API, так и сложный Observable с данными.

Providing значения обычно реализуется в связке с InjectionToken. Этот объект ключ для DI-механизма. Сначала вы говорите: Я хочу получить вот эти данные по такому ключу. А позже приходите к DI и спрашиваете: Есть ли что-то по этому ключу?

Ну и частый кейс проброс глобальных данных из корня приложения.

Лучше посмотреть это сразу в действии, поэтому давайте взглянем на stackblitz с примером:



Итак, в примере мы получили зависимость из DI вместо того, чтобы импортировать ее как константу из другого файла напрямую. И почему нам от этого лучше?

  • Мы можем переопределить значение токена на любом уровне дерева DI, никак не меняя компоненты, которые его используют.
  • Мы можем мокировать значение токена подходящими данными при тестировании.
  • Компонент полностью изолирован и всегда будет работать одинаково, независимо от контекста.


Providing фабрики


На мой взгляд, это самый мощный инструмент в механизме внедрения зависимостей Angular.

Вы можете создать токен, в котором будет результат комбинации и преобразования значений других токенов.

Вот еще один stackbitz с подробным примером создания фабрики со стримом.



Можно найти много кейсов, когда providing фабрики экономит время или делает код более читабельным. Иногда мы внедряем зависимости в компоненты только ради того, чтобы совместить их или преобразовать в совершенно иной формат. В предыдущей статье я рассматривал этот вопрос подробнее и показывал альтернативный подход к решению таких ситуаций.

Providing существующего экземпляра


Не самый частый случай, но этот вариант бывает очень полезным инструментом.

Вы можете положить в токен сущность, которая уже была создана. Хорошо работает в связке с forwardRef.

Посмотрите еще один пример со stackblitz с директивой, которая имплементирует интерфейс и подменяет собой другой токен через useExisting. В этом примере мы хотим переопределить значение токена только в области видимости DI для дочерних компонентов элемента, на котором висит директива. Причем директива может быть любой главное, что она реализует необходимый интерфейс.



Хитрости с DI-декораторами


DI-декораторы позволяют сделать запросы к DI более гибкими.

Если вы не знаете все четыре декоратора, советую почитать вот эту статью на Медиуме. Статья на английском, но там очень классные и понятные визуализации по теме.

Не многие также знают, что DI-декораторы можно использовать в массиве deps, который готовит аргументы для фабрики в providers.

providers: [   {     provide: SOME_TOKEN,     /**      * Чтобы фабрика получила декорированное значение, используйте такой      * [new Decorator(), new Decorator(),..., TOKEN]      * синтаксис.      *      * В этом случае вы получите null, если не будет значения для      * OPTIONAL_TOKEN      */     deps: [[new Optional(), OPTIONAL_TOKEN]],     useFactory: someTokenFactory   } ]


Фабрика токена


Конструктор InjectionToken принимает два аргумента.

Второй аргумент объект с конфигурацией токена.

Фабрика токена это функция, которая вызывается в момент, когда кто-то запрашивает этот токен в первый раз. В ней можно посчитать некое стандартное значение для токена или даже обращаться к другим DI-сущностям через функцию inject.

Посмотрите пример реализации функционала стрима нажатия кнопок, но уже на фабрике токена.



Заключение


DI в Angular удивительная тема: на первый взгляд, в нем не так много различных рычагов и инструментов для изучения, но можно писать и говорить часами о тех возможностях и способах применения, которые они нам дают.

Надеюсь, этой статьей мне удалось дать вам фундамент, на основе которого вы сможете придумать собственные решения для упрощения работы с данными в ваших приложениях и библиотеках.
Источник: habr.com
К списку статей
Опубликовано: 26.08.2020 16:11:24
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Блог компании tinkoff

Javascript

Angular

Typescript

Di

Dependency injection

Inversion of control

Ng

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru