Как правильно построить сервис? - PullRequest
0 голосов
/ 11 июня 2018

Счастливые разработчики в понедельник!

У меня к вам вопрос, на который я не смог ответить сам.

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

Теперь мне нужно выполнить все эти вызовы API, прежде чем мое приложение будет доступно пользователю.

Теперь мой вопрос: «Как правильно построить структуру приложения, в которой вы зависите от данных».

В настоящее время реализовано решение:

Каждый сервис сам по себе имеетнесколько функций, которые затем создают несколько HTTP-запросов на получение.

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

Теперь, как правильно это сделать? Мне нужноУ меня есть функция, которую я могу вызвать, которая извлекает все данные, необходимые для моего приложения, и я должен иметь возможность вызывать эту функцию из любого компонента и / или службы в моем приложении, не создавая циклическую зависимость.

Как бы вы, ребята, решили это?И есть ли лучший метод для этого?

** К вашему сведению, это не стандартное приложение, а «киоск».Сначала мы хотим получить все данные, чтобы приложение практически никогда не загружалось.Кроме того, когда я вызываю эту функцию, чтобы восстановить все данные.**

Пример кода основного обслуживания:

    constructor(
    private testservice1: TestService1,
    private testservice2: TestService2,
    private testservice3: TestService3,
    private testservice3: TestService4
) {
    this.loading = true;

    this.getApplicationLogic()
     .then(() => {
        this.loading = false;
     })

}

public getApplicationLogic() {
    return new Promise((resolve, reject) => {
        testservice1.getTest()
            .then(
                res => {
                    testservice1.setTestConfig(res);
                    return this.testservice2.getTest2();
                },
                msg => {
                    throw new Error(msg)
                })
            .then(
                res => {
                    testservice2.setTestConfig(res);
                    return this.testservice3.getTest3();
                },
                msg => {
                    throw new Error(msg)
                })
            .then(
                res => {
                    testservice3.setTestConfig(res);
                    resolve();
                },
                msg => {
                    throw new Error(msg)
                })
    });
}

Ответы [ 3 ]

0 голосов
/ 11 июня 2018

У вас есть 2 вопроса:

  1. Как загрузить данные из API при запуске приложения.Для этого вам нужно использовать токен APP_INITIALIZER.Официальные документы здесь и объяснение учебника здесь .

  2. Избегайте циклической зависимости.Я думаю, что ваша основная служба не может (и не должна) использоваться повторно.Вызовы API по своей природе должны быть асинхронными, хотя кажется, что вы пытаетесь выполнить их в определенном порядке.Не совсем понятно, что вы пытаетесь сделать, когда говорите «всякий раз, когда я импортирую этот основной сервис из другого сервиса» - принимая ваш пример кода, очевидно, что ни один из тест-сервисов 1..4 не сможет импортировать main.Поэтому, если у вас есть какой-то новый сервер (testservice5), которому для загрузки 1..4 требуется FIRST, то testservice5 может импортировать Main, а затем выполнять свою работу.Даже если testservice5, например, выполняет тот же вызов API, что и testservice1 (конечно, это означает, что у вас будет дублирование кода).

Лучшим решением для (2) было бы НЕ проектировать вокруг наличиясервисы выполняются в определенном предопределенном порядке, но позволяют каждому сервису запускаться независимо друг от друга, хранить данные и иметь своего рода глобальный трекер, который обновляется при завершении каждого сервиса (возвращает данные).

ДляНапример, при запуске приложения скажем, что вы хотите завершить 4 службы.Запустите первый, в результате вы обновите флаг до 1 и запустите событие.Ваш второй сервис прослушивает это событие и запускается.В результате вы обновляете флаг до 2 и снова запускаете событие.Служба 3 прослушивает это событие и запускается, обновляет флаг и т. Д.

Таким образом, вы можете использовать все 4 службы в определенном порядке при запуске, но при этом каждая служба будет иметь отдельную отдельную «вещь», которую выповторное использование позже, когда приложение работает.

0 голосов
/ 11 июня 2018

Обычно я структурирую сервисы с помощью общего сервиса приложений, который содержит глобальные настройки (например, URL-адрес внутреннего сервера), сервис http, который работает с общими запросами http, например,

export class MyHttpService{
  constructor(
  private http: HttpClient,
  private app: AppstateService,
  private log: LogService
) { }

getRest<T>(api: string)  {
  let opts = this.getOptions();
  return this.http.get<T>(this.app.backurl + "/api/v1/" + api, opts);
}

, и сервис API, который реализует сервисы API.высокоуровневый API, например

export class MyapiService {
   constructor(private myhttp: MyHttpService) {}

GetOperations(pt_id: number) {
 this.myhttp.getRest<DashboardOperations>( "GetDashboardOperations?pt_id=" 
  + pt_id ).pipe(map(resp=> resp.data));
}

последний компонент имеет дело только со службой API для получения данных с подпиской.

Если вы не хотите, чтобы ваше приложение получало все данные каждыйкогда он обновляет информацию, вы можете использовать pouchdb для локального хранения данных и синхронизации с сервером (см. https://www.sitepoint.com/offline-web-apps-service-workers-pouchdb/)

0 голосов
/ 11 июня 2018

Вы можете обойти циклические зависимости, введя Injector вместо одной из служб, вызывающих циклическую зависимость

private testservice1:Testservice1;
constructor(/*private testservice1:Testservice1*/ injector:Injector) {
  setTimeout(() => this.testservice1 = injector.get(Testservice1));
}

Я не знаю сложности вашего кода.Но если вы пересекаете любую круговую зависимость, вы можете применить это.

...