Рендеринг на основе времени наблюдаемых в Angular без подавляющего обнаружения изменений - PullRequest
0 голосов
/ 04 декабря 2018

В нашем приложении Angular имеется ряд компонентов, которым необходимо регулярно отображать новые значения каждую секунду, уникальные для каждого компонента (обратные отсчеты, отметки времени, прошедшее время и т. Д.).Наиболее естественным способом является создание наблюдаемых, которые используют фабричные функции RxJS timer и interval.Тем не менее, они вызывают обнаружение угловых изменений на каждом интервале для всего приложения столько раз, сколько была вызвана функция интервала .Если на странице присутствуют десятки компонентов, это инициирует обнаружение изменений для всего приложения десятки раз в секунду или период времени, что приводит к значительному снижению производительности.

До сих пор я пытался решить эту проблему двумя способами.Хороший ответ на любой из них был бы очень полезен - в идеале обаЯ хочу избежать ручного запуска обнаружения изменений и вместо этого полагаться на новые значения, генерируемые Observables, и иметь стратегию обнаружения изменений асинхронного канала / OnPush, отвечающую за запуск обнаружения изменений.Если это невозможно, я хотел бы понять, почему.

  1. Есть ли способ отключить или запретить функциям RxJS timer или interval запускать обнаружение изменения угла?Использование NgZone zone.runOutsideAngular(() => this.interval$ = interval(1000) ... ) не позволяет этого сделать.Пример StackBlitz: https://stackblitz.com/edit/angular-zo5h39
  2. В качестве альтернативы, если я создаю наблюдаемый поток, используя RxJS Subject в сочетании с setInterval, вызываемым внутри zone.runOutsideAngular, почему обнаружение изменений не запускается для дочернего компонента, когдановое значение выбрасывается из темы?Пример StackBlitz: https://stackblitz.com/edit/angular-yxdjgd

1 Ответ

0 голосов
/ 04 декабря 2018
  1. Есть ли способ отключить или предотвратить запуск функции таймера или интервала RxJS обнаружения изменения угла?Использование NgZone zone.runOutsideAngular (() => this.interval $ = interval (1000) ...), по-видимому, не делает этого.

Это потому, что наблюдаемые являются холодными, и значениепродюсер (setInterval) выполняется только тогда, когда происходит подписка.Хотя этот код выполняется за пределами угловой зоны:

() => this.interval $ = интервал (1000) ...

, на самом деле он не сразувызовите производителя значений внутри оператора interval.Это будет позже вызвано, когда AsyncPipe в IntervalInnerComponent подписывается.И это происходит во внутренней угловой зоне:

enter image description here

Используя тему в следующей альтернативе, вы делаете ее горячей и подписываетесь сразу за пределами угловой зоны.

В качестве альтернативы, если я создаю наблюдаемый поток с использованием субъекта RxJS в сочетании с setInterval, вызываемым внутри zone.runOutsideAngular ... создаются значения setInterval (на них можно подписаться вручную), но асинхронный канал не запускаетсяобнаружение изменений

Поскольку Async Pipe не запускает обнаружение изменений.Он просто отмечает компонент и всех его предков для проверки во время следующего обнаружения изменений, когда бы он ни был.См. ответ или эту статью для получения более подробной информации.Zone.js запускает обнаружение изменений.Но поскольку вы запускаете setInterval за пределами угловой зоны, это не сработает.В этой настройке у вас есть несколько вариантов:

  • inject ChangeDetectorRef и ручное инициирование обнаружения изменений для компонента и его предков
  • inject ApplicationRef и ручное инициирование обнаружения изменений длявсе приложение
...