DevGang
Авторизоваться

Используйте RxJS для изменения поведения приложения на основе видимости страницы 

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

К сожалению, не все серверы предоставляют push-уведомления, такие как веб-сокеты, поэтому мы, скорее всего, создадим систему опроса, которая отправляет и извлекает результат из REST API один раз в течение данного цикла.

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

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

API видимости страницы

Page Visibility API позволяет вашему приложению знать , когда страница видна пользователю. Эта основная информация позволяет создавать веб-страницы, которые ведут себя по-разному, когда их не просматривают.

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

Пример использования (Polling)

В нашем примере мы создадим службу уведомлений, которая будет опрашивать уведомления с сервера. (Мы будем использовать Angular, но он будет работать с любой другой реализацией)

@Injectable({
  providedIn: 'root'
})
export class NotificationsService { constructor(private http: HttpClient) { } 
  getNotifications() {
    return http.get('http://api').pipe(
      poll(1000)
    )
  }
}

Давайте создадим бесконечный оператор опроса с RxJS, комбинируя операторы timer и concatMap.

export function poll(period: number, initialDelay = 0) {
  return function(source: Observable) {
    return timer(initialDelay, period).pipe(concatMapTo(source));
  }
}

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

В нашем случае мы используем наблюдаемый timer, который занимает период времени и начальную задержку (которая по умолчанию равна нулю, поскольку мы обычно хотим немедленно начать опрос), и конкатенируем observable. Это даст нам бесконечную функциональность опроса.

Далее мы создадим один последний пользовательский оператор RxJS, который использует API видимости страницы вместе с двумя встроенными операторами для достижения желаемой функциональности:

export function whenPageVisible() {
  const visibilitychange$ = fromEvent(document, 'visibilitychange').pipe(
    shareReplay({ refCount: true, buffer: 1 })
  );
 
  const pageVisible$ = visibilitychange$.pipe(
    filter(() => document.visibilityState === 'visible')
  );
 
  const pageHidden$ = visibilitychange$.pipe(
    filter(() => document.visibilityState === 'hidden')
  ); 

  return function (source: Observable) {
    return source.pipe(
      takeUntil(pageHidden$),
      repeatWhen(() => pageVisible$)
    )
  }
}

visibilitychange$ использует fromEvent, который добавляет слушатель событий visibilitychange для объекта документа. Поскольку мы хотим создать слушатель событий только один раз, мы используем оператор shareReplay.

Затем мы создаем две наблюдаемые вариации на основе visibilitychange$: одна для того, когда страница видима, а другая - когда она скрыта.

Последний шаг - связать исходный код с двумя встроенными операторами, которые делают всю работу за нас:

Оператор takeUntil принимает Observable. Когда он отправляет событие, он автоматически отписывается от наблюдаемого источника. В нашем случае, когда пользователь переключается, вкладка pageHidden$ будет отправлять событие и вызывать прекращение опроса уведомлений.

Оператор repeatWhen делает обратное; Требуется функция, которая возвращает наблюдаемую. Когда это наблюдаемое отравляет событие, оно повторно подписывается на наблюдаемый источник. В нашем случае, когда пользователь вернется в наше приложение, он повторно подпишется на опрос уведомлений. Это так просто 😀

@Injectable({
  providedIn: 'root'
})
export class NotificationsService {
  constructor(private http: HttpClient) { } getNotifications() {
    return this.http().pipe(
      poll(1000),
      whenPageVisible()
    )
  }
}

Небольшой совет: рассмотрите возможность добавления retry в случае ошибки.

В дополнение

Начиная с RxJS v6.5 , мы можем сделать этот пример еще короче и использовать partition:

import { partition } from 'rxjs';

export function whenPageVisible() {
  ...
  const [pageVisible$, pageHidden$] = partition(
    visibilitychange$, 
    () => document.visibilityState === 'visible'
  );
 
  return function(source: Observable) {
    return source.pipe(
      takeUntil(pageHidden$),
      repeatWhen(() => pageVisible$)
    );
  };
}

Перевод статьи: Use RxJS to Modify App Behavior Based on Page Visibility

#Angular #RxJS
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу