Angular - async / await Observable toPromise update передает новые данные BehaviorSubject, возвращая обещание

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

Итак, мои вопросы:

  1. Имеет ли смысл создавать новый BehaviorSubject при каждом вызове getTeacherProfile (), getTeacherProfileInfo (), getTeacherProfileByProfileId (), потому что это не создает новую переменную и никакие предыдущие подписчики не будут уведомлены?

  2. Будет ли правильным лучшим шаблоном инициализировать один раз в конструкторе, например

this.broadCast = new BehaviorSubject<TeacherProfileModel>();

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

this.broadCast.next(data);
  1. Вместо подписки внутри методов получения Promise .then (), разве не является стандартной практикой делать все .subscribe ((data) = ›{внутри ngOnInit () один раз за жизненный цикл компонента?

  2. Также нет ngOnDestroy () или отказа от подписки, что, я считаю, является стандартной практикой при подписке на любой BehaviorSubject, потому что, если вы этого не сделаете, это может вызвать утечки памяти и неожиданные результаты?

  3. Может ли это быть вызвано порядком, в котором методы вызываются связанным кодом, который создает несогласованное взаимодействие с пользователем из зависимого кода, который подписывается на BehaviorSubjects, который может быть изменен / переназначен и забыт, что приведет к неожиданным и непредсказуемым результатам?

Заранее спасибо за помощь!

ВЫДЕРЖКИ КОДА

учитель.service.ts

  async getTeacherProfile(): Promise<TeacherProfileModel> {
    if (this.teacherProfileId > 0) {
      var data = await this.crudService.get<TeacherProfileModel>("/tProfile/GetTeacherProfileData",
        new HttpParams().set('teacherProfileId', this.teacherProfileId.toString())).toPromise();
      this.broadCast = new BehaviorSubject<TeacherProfileModel>(data);
      this.teacherProfile = data;
      this.personalizedURL = this.teacherProfile.PersonalizedUrl;
    }
    else {
      if (this.teacherProfileId === 0) {
        this.initialiseTeacherProfile();
        this.commonService.isDefaultImageFlag = true;
      }
      this.broadCast = new BehaviorSubject<TeacherProfileModel>(this.teacherProfileData);
    }

    return this.teacherProfile;
}

async getTeacherProfileInfo(url: string): Promise<TeacherProfileModel> {
    var data = await this.crudService.get<TeacherProfileModel>("/teacherProfile/GetTeacherProfileInfo",
      new HttpParams().set('personlizedUrl', url)).toPromise();
    this.broadCast = new BehaviorSubject<TeacherProfileModel>(data);
    this.teacherProfile = data;
    this.personalizedURL = this.teacherProfile.PersonalizedUrl;
    return this.teacherProfile;
} 

async getTeacherProfileByProfileId(teacherProfileId:any): Promise<TeacherProfileModel> {
    this.teacherProfileId = teacherProfileId;
    this.imageUrl = localStorage.getItem("userImageUrl");
  
    var data = await this.crudService.get<TeacherProfileModel>("/teacherProfile/GetTeacherProfileData",
      new HttpParams().set('teacherProfileId', this.teacherProfileId.toString())).toPromise();
    this.broadCast = new BehaviorSubject<TeacherProfileModel>(data);
    this.teacherProfile = data;
    this.personalizedURL = this.teacherProfile.PersonalizedUrl;
    return this.teacherProfile;
}

profile.component.ts

ngOnInit() {
    this.teacherService.getTeacherProfile().then((response: any) => {
         this.teacherService.broadCast.subscribe(data => {
              if(data !== undefined) { 
                   //do something  
              }
         });
    });
}

учитель-профиль-edit.component.ts


  previewChanges() {
    this.commonService.userProfilePic = localStorage.getItem('userImageUrl');
    this.commonService.isStudentUser = false;
    this.teacherService.broadCast.next(this.teacherProfile);
  }


  private getTeacherProfileData() {
    this.teacherService.getTeacherProfile().then((response: any) => {
      this.teacherService.broadCast.subscribe(data => {
        if(data !== undefined) {
          this.teacherProfile = data;
          this.onProfileStatusChange(this.teacherProfile.IsProfileStatusPrivate);
          this.shortIntroLength = this.introLength - data.ShortIntroduction.length;
          if (data.TeacherQualifications.length === 0) {
            this.addQualification();
          }
        } else {
          var err = 'Error'; this.toastr.error('Oops! Something went wrong! '+err); throw err;
        }
      });
    });
  }


person BadDevShop    schedule 16.01.2021    source источник


Ответы (2)


  1. Прежде всего, вам не нужно создавать новый объект поведения каждый раз, когда вы можете просто передать значение null с помощью метода .next (null), а также, если вы подписались на это, вы можете поставить условие, что ответ от объекта поведения не должен быть нулевым.

  2. Определенно, это правильный метод использования BehaviorSubject. даже вы можете проверить официальный сайт https://rxjs-dev.firebaseapp.com/api/index/class/BehaviorSubject

  3. Я не получил этого, но я предлагаю вам перейти на подписку и поместить все свои подписки в подписку, а на крючке уничтожения компонента полностью отказаться от подписки. https://medium.com/thecodecampus-knowledge/the-easiest-way-to-unsubscribe-from-observables-in-angular-5abde80a5ae3

  4. пройдите по ответу 3. Да, если вы не укажете, что он просто работает в фоновом режиме, если он не уничтожен.

person hardik godhani    schedule 16.01.2021

Что ж, все, что ты сказал, правильно,

Причина, по которой я предполагаю, что он переинициализировал, была связана со следующим кодом:

this.teacherService.getTeacherProfile().then((response: any) => {
     this.teacherService.broadCast.subscribe(data => {
          if(data !== undefined) { 
               //do something  
          }
     });
});

getTeacherProfile() возвращает Promise, а затем подписывается на BehaviorSubect, по сути подписываясь на новый BehaviorSubject. Конечно, так делать не стоит.

Предполагая, что crudService.get() - это просто вызов Http, вы можете просто вернуть Observable, и любую операцию, которая вам нужна, можно выполнить (используя rxjs), подключив его к конвейеру и нажав на него, например, кэширование ответа.

teacherProfileModelResponseCache;
getTeacherProfile(): Observable<TeacherProfileModel> {
    if (this.teacherProfileId > 0) {
        return this.crudService.get<TeacherProfileModel>("/tProfile/GetTeacherProfileData",
    new HttpParams().set('teacherProfileId', this.teacherProfileId.toString()))
        .pipe(
            tap(x=>{
                this.teacherProfileModelResponseCache = x;
                this.personalizedURL = x.PersonalizedUrl;
            })
        )
    }
    else {
        if (this.teacherProfileId === 0) {
            this.initialiseTeacherProfile();
            this.commonService.isDefaultImageFlag = true;
        }
    }

    return of(teacherProfileModelResponseCache);
}

А на своем профиле учителя-edit.component.ts вы просто подписываетесь на него и делаете то, что требуется.

private getTeacherProfileData() {
    this.teacherService.getTeacherProfile().subscribe(data => {
        if(data !== undefined) {
            this.teacherProfile = data;
            this.onProfileStatusChange(this.teacherProfile.IsProfileStatusPrivate);
            this.shortIntroLength = this.introLength - data.ShortIntroduction.length;
            if (data.TeacherQualifications.length === 0) {
                this.addQualification();
            }
        } else {
            var err = 'Error'; this.toastr.error('Oops! Something went wrong! '+err); throw err;
        }
    });
}
person j4rey    schedule 16.01.2021