Почему я получаю сообщение об ошибке «Невозможно получить доступ к« переменной »до инициализации» от самого подписчика? - PullRequest
2 голосов
/ 21 октября 2019

В моем приложении Angular 8 у меня есть компонент, который подписывается на сервис и ожидает уведомления о том, что сервис загружен следующим образом:

constructor(public contentService: ContractService) {
    let self = this;
    let sub = contentService.loaded.subscribe(function(loaded) {
        if (loaded) {
            self.loading = false;
            if (sub) {
                sub.unsubscribe();
            }
        }
    });
}

В большинстве случаев это работает правильно, но иногда я вижуследующее сообщение об ошибке:

ERROR ReferenceError: Cannot access 'sub' before initialization
    at SafeSubscriber._next (abstract-content.component.ts:51)
    at SafeSubscriber.__tryOrUnsub (Subscriber.js:185)
    at SafeSubscriber.next (Subscriber.js:124)
    at Subscriber._next (Subscriber.js:72)
    at Subscriber.next (Subscriber.js:49)
    at BehaviorSubject._subscribe (BehaviorSubject.js:14)
    at BehaviorSubject._trySubscribe (Observable.js:42)
    at BehaviorSubject._trySubscribe (Subject.js:81)
    at BehaviorSubject.subscribe (Observable.js:28)
    at Observable._subscribe (Observable.js:76)

Как можно понять из названия, abstract-content-component является родительским классом, который имеет несколько реализаций, поэтому он вызывается из дочернего класса, но фактически является пустой оболочкой безсобственная логика, которую я использую, чтобы упростить переключение шаблонов.

Сообщение об ошибке кажется мне бессмысленным (строка 51 в данном случае - это проверка if(sub), которую я добавил, потому что я видел то же самоеошибка в строке после), потому что как подписка может не существовать, если мы находимся внутри собственного обработчика событий? Я успешно использую этот шаблон в других местах, почему здесь проблема?

Ответы [ 2 ]

2 голосов
/ 21 октября 2019

Вы можете избавиться от этой ошибки, объявив sub как атрибут компонента.

sub: Subscription = new Subscription();
// ...

constructor(public contentService: ContractService) {
    let self = this;
    this.sub = contentService.loaded.subscribe(function(loaded) {
          // ...
          this.sub.unsubscribe();
          // ...
    });
}

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


Чтобы убедиться, что подписчик не получает никаких других значений после того, как сервис вернет первое, вы действительно можете отписаться послеего «работа» выполнена (как вы делали), но объявите переменную sub в качестве атрибута и инициализируйте ее с помощью new Subscription();


, чтобы убедиться, что подписка не зависаетВы можете отписаться от него в ngOnDestroy в компоненте:

ngOnDestroy() {
  // ...
  this.sub.unsubscribe();
  // ...
}

Кроме того, если вы чувствуете, что вам нужно лучше понять, как Observables шаблонные работы см. угловые документы для наблюдаемых

0 голосов
/ 21 октября 2019

Вы проверяете на sub, прежде чем установить sub.

Если вы просматриваете свой код логически и устанавливаете пошагово, вы увидите, что вы объявляете sub с начальным значением. Однако это начальное значение является функцией или, в частности, в этом случае подпиской. Что все еще в порядке.

Однако проблема заключается в том, что в самой функции вы полагаетесь на устанавливаемую переменную sub. А это не так, потому что вы находитесь в процессе его установки, во время его объявления.

Отсюда ошибка:
Cannot access 'sub' before initialization

На самом деле неясно, что выпытаетесь сделать, потому что логически это выглядит, как будто вы пытаетесь подписаться на что-то, но если вы подписались на это, отписаться? Но вы не должны делать это в отписке.

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

// I assume you have a variable "loaded" above, because you've set self to this in your code
private unsubscribeStream = new Subject();

this.contentservice.loaded.pipe(
  filter(x => x !== null), // Filter out where x doesn't exist
  takeUntil(this.unsubscribeStream)).subscribe(loaded => {
    this.loaded = loaded;
  });

// When the component is destroyed, call the next value of unsubscribe stream which will unsubscribe from anything we've set to takeUntil
ngOnDestroy() {
   this.unsubscribeStream.next();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...