Причина, по которой обработчик запускается дважды, заключается в том, что вы никогда не отмените подписку на услугу. pollingDataReceived
Тема, а вы несколько раз нажимаете на эту тему. Вероятно, ваш сервис был создан один раз, а ваши компоненты были повторно созданы несколько раз с повторным посещением страницы. Компоненты были уничтожены, хотя их подписки на ту же тему оставались нетронутыми.
Самый простой способ обойти это отписаться от этой темы в методе компонента ngOnDestroy
, как предложил @ashish.gd .
Создание новых объектов каждый раз (, как предлагается здесь ), вероятно, приведет к утечкам памяти. Поскольку ваши старые подписки будут продолжать слушать старые темы. Осторожно.
В то время как самым простым способом было бы отписаться от pollingDataReceived
Тема, лучшим способом было бы иметь ваш сервис pollForData()
для возврата Observable.
Если вам не нужно, чтобы несколько потребителей читали один и тот же pollingDataReceived
Тема - вам не нужно иметь там подписку. Вот пример кода, чтобы отразить эту идею:
pollForData = (id: string) : Observable => {
return Observable.interval(environment['pollingInterval'])
.concatMap(() => this.getAnalysisById(id))
.takeWhile(data => data.status === 'questions')
// other handling logic goes here
// .map(), .switchMap(), etc
// NOTE: no subscription here
}
и в контроллере вы можете сделать что-то вроде
// just an utility subject to track component destruction
onDestroy$ = new Subject();
someEventHandler() {
this.pollForData(this.id).pipe(
// this will ensure that subscription will be completed on component destruction
takeUntil(this.onDestroy$)
).subscribe((data) => {
this.analysis = data.analysisData;
myNavigator.navigateToPageByStatus(myPage);
}, (err) => { console.log(err); });
}
ngOnDestroy() {
this.onDestroy$.next(void 0);
}
-
ПРИМЕЧАНИЕ 1 : похоже, что в настоящее время ваша услуга предоставляется на уровне модуля, что означает, что если у вас когда-нибудь будет два потребителя, запрашивающих pollForData(id)
одновременно (например, два компонента на одной странице) - оба эти запроса будут «записываться» в одного и того же субъекта . Поведение, склонное к ошибкам.
ПРИМЕЧАНИЕ 2 : в настоящее время в вашем коде takeWhile
предикат не будет запускаться, пока вы не получите новое событие в потоке
Observable.interval(environment['pollingInterval'])
.takeWhile(() => !stopPollingForStatus)
Это означает, что у вас будет ненужная подписка в памяти на environment['pollingInterval']
раз. Это не должно быть критичным, но это может быть неприятно в зависимости от времени.
-
Надеюсь, это поможет, удачного кодирования!