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

  • Вызов службы для установки некоторых данных
  • Получить обновление
  • Распространите эти обновления на необходимые компоненты в пользовательском интерфейсе, чтобы получить обновление теневой модели DOM.

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

Если есть действительно длительные действия, вам может не хватать помощи второго автономного микросервиса, который может отслеживать и предоставлять ресурсы RESTful. Когда речь идет о необходимости обновления пользовательского интерфейса в реальном времени с помощью триггеров событий. Websocket или сервисный работник PWA являются предпочтительным маршрутом. Служба будет напрямую отправлять сообщение из службы экземпляру PWA с сообщением об обновлении, инструктируя его снова получить данные службы.

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

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

async created() {
  const summaryPromise = this.reportManager.getTeamIndicators();
  if (this.overallScore === null && !this.uncompletedHealthCheck) {
    reportManager.getSettings().then(settings => {
      this.healthCheckSettings = {
        dayOfWeek: settings.dayOfWeek,
        frequency: settings.frequency,
        loading: false
      };
    }, error => {
      this.logger.warn({ title: 'Failed to get health check configuration', exception: error });
    });
  }
  await summaryPromise;
  if (this.healthCheckData?.lastUpdated) {
    this.suggestionsManager.fetchSuggestions();
  }
  this.isLoading = false;
}

Если вы не знакомы с таким кодом, то это функция created, предлагаемая Vue. Здесь находится набор динамических нагрузок с необязательным awaiting в зависимости от точного состояния системы. Неважно, если промисы заморожены, потому что компонент выгружен, и контроль над ними мне точно не нужен.

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