Как стать автором
Обновить

@artstesh/postboy и асинхронные события: избавляемся от промежуточных сервисов в Angular

Уровень сложностиПростой
Время на прочтение4 мин
Количество просмотров373

Асинхронное управление событиями в Angular-приложениях — одна из основных задач при разработке, особенно если приложение активно взаимодействует с динамическими данными или имеет сложную архитектуру. Зачастую для решения этой задачи разработчики используют подписки и/или промежуточные сервисы. Несмотря на популярность этих подходов, они могут приводить к избыточным зависимостям, высокому уровню связности и сложному коду.

Библиотека @artstesh/postboy предоставляет альтернативный взгляд на эту проблему: она позволяет избавиться промежуточных сервисов и использовать асинхронные события простым и лаконичным способом.

Как отправлять и обрабатывать асинхронные события

*В данном опусе пропущены все объяснения того, что такое @artstesh/postboy и как его устанавливать, за этой информацией можете заглянуть сюда или на сайт проекта.

Отправка событий

Для публикации событий в @artstesh/postboy используется удобный интерфейс, позволяющий публиковать события с параметрами или без них. Пример отправки события:

// Отправка события без параметров
postboy.fire(new SimpleEvent());

// Отправка события с параметрами
postboy.fire(new EventWithParams('Hello, world!'));

В этом примере библиотека полностью берет на себя задачу передачи сообщений. Благодаря этому вам не нужно вручную связывать компоненты через сервисы или использовать Input/Output. Также стоит отметить, что и complete подписок библиотека так же возьмет на себя (в конце жизненного цикла модуля в котором обитает компонент).


Обработка событий

Для обработки событий достаточно подписаться через саму библиотеку. Это не стандартная подписка RXJS/Observable, а способ привязки, при котором (с некоторыми оговорками) стирается необходимость в явных отписках.

Пример обработки событий:

// Подписка на событие без параметров
postboy.sub(SimpleEvent).subscribe(() => {
  console.log('Событие simpleEvent выполнено!');
});

// Подписка на событие с параметрами
postboy.sub(EventWithParams).subscribe(message => {
  console.log('Получено сообщение:', message);
});

Теперь при вызове postboy.fire(new SimpleEvent()) метод обработки автоматически выполнится. Если событие передавало данные, они будут доступны в обработчике.


Чем это лучше традиционных подходов

Преимущества подхода @artstesh/postboy:

Сокращение кода: Больше никакого создания промежуточных сервисов. Одного экземпляра Postboy достаточно для сообщения между всеми частями приложения (либо отдельными его модулями, если такое разделение будет необходимо, тогда мы разделяем зоны событий, выделяя на каждую зону отдельный регистратор).

Повышение читаемости кода: Нет громоздких цепочек подписок и управлений состояниями. Роль каждого компонента становится явно определённой.

Ослабление проблемы утечек памяти: При использовании библиотеки не нужно явно отписываться от событий — как это необходимо, например, в случае с RXJS, система вызовет complete() на всех подписках завершаемого модуля.

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


Разница подходов

Давайте рассмотрим пример синтетического сценария: у нас есть кнопка, которая инициирует запрос и показывает результат пользователю в компоненте.

Без @artstesh/postboy

В стандартной архитектуре Angular это могло бы выглядеть примерно так:

//middle.service.ts

import {Injectable} from "@angular/core";
import {ReplaySubject} from "rxjs";

@Injectable({providedIn: 'root'})
public class MiddleService {
  message$ = new ReplaySubject<string>()
}
// button.component.ts
import { Component } from '@angular/core';
import { DataService } from './data.service';

@Component({
  selector: 'app-button',
  template: '<button (click)="loadData()">Загрузить данные</button>',
})
export class ButtonComponent {
  constructor(private dataService: DataService, private middle: MiddleService) {}

  loadData() {
    this.dataService.loadData().subscribe((data) => {
      this.middle.message$.next(data.result);
    });
  }
}
// display.component.ts
import {Component, Input, OnInit} from '@angular/core';

@Component({
  selector: 'app-display',
  template: '{{ data }}',
})
export class DisplayComponent implements OnInit {
  data: string = '';

  constructor(private middle: MiddleService) {
  }

  ngOnInit() {
    this.middle.message$.subscribe(d => this.data = d);
  }
}

С @artstesh/postboy

Теперь перепишем этот пример с использованием нашей библиотеки:

// button.component.ts
import { Component } from '@angular/core';
import { AppPostboyService } from './app-postboy.service';

@Component({
  selector: 'app-button',
  template: '<button (click)="loadData()">Загрузить данные</button>',
})
export class ButtonComponent {

  constructor(private postboy: AppPostboyService) {}

  loadData() {
    this.postboy.fireCallback(new LoadDataCommand(),response => {
      // Логика после загрузки данных
      const data = { result: 'Данные успешно загружены' };
      this.postboy.fire(new DataLoadedEvent(data));
    });
  }
}
// display.component.ts
import {Component, OnInit} from '@angular/core';
import {Postboy} from '@artstesh/postboy';

@Component({
  selector: 'app-display',
  template: '{{ data }}',
})
export class DisplayComponent implements OnInit {
  data: string = '';

  constructor(private postboy: AppPostboyService) {}

  ngOnInit() {
    this.postboy.sub(DataLoadedEvent).subscribe(data => {
      this.data = data.result;
    });
  }pp

Для пары компонентов разница, возможно, не выглядит действительно впечатляющей, но с увеличением масштаба разница становится все более заметной - оригинальный код обрастает все большим количеством подписок и новых сервисов, а управляемый postboy все так же зависит только от AppPostboyService


Заключение

Асинхронное управление событиями с библиотекой @artstesh/postboy позволяет сделать код в Angular-приложениях более понятным и простым в сопровождении. Благодаря тому, что вам больше не нужно создавать промежуточные сервисы, объединять компоненты через Input/Output, работа с событиями становится гораздо проще.

Не забудьте ознакомиться с другим функционалом библиотеки, а еще я буду рад услышать предложения по улучшению и дополнению функционала.

Теги:
Хабы:
Всего голосов 3: ↑1 и ↓2+1
Комментарии0

Публикации

Работа

Ближайшие события