Я определяю наблюдаемый объект (result$) в компоненте и отображаю его в его шаблоне через асинхронный канал. Наблюдаемый объект представляет собой комбинацию двух других наблюдаемых (первый $, второй $) через combLatest. Если один из наблюдаемых или оба излучаются слишком рано (до того, как я нашел ngAfterContentInit), результирующий наблюдаемый не будет излучать значение.
Компонент: не работает
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
result$: Observable<number>;
first$ = new Subject<number>();
second$ = new Subject<number>();
constructor() {}
ngOnInit(){
this.result$ = combineLatest(
this.first$,
this.second$
).pipe(
map(([first, second]) => {
// This is not printed to the console
console.info('combined obs emitted value');
return first + second;
})
);
console.info('first and second emit value');
this.first$.next(2);
this.second$.next(4);
}
ngAfterContentInit() {
console.info('ngAfterContentInit');
}
}
Порядок выполнения такой:
1.первое и второе значение излучения
2.ngAfterContentInit
Мое предположение здесь заключается в том, что в ngAfterViewInit шаблон был отрендерен и подписки были сделаны. Поскольку наблюдаемые выдают значение перед этим, компонент не уведомляется. Это может означать только то, что полученный наблюдаемый объект является холодным (поэтому вам необходимо подписаться, прежде чем он выдаст значение). 2 наблюдаемых являются субъектами, поэтому я предполагаю, что субъекты являются холодными наблюдаемыми. Это правильно?
Если я задержу выпуск first$ и second$, все работает: Компонент: first$ и second$ выпускаются позже @Компонент({ селектор: 'мое-приложение', Url-шаблона: './app.component.html', styleUrls: [ './app.component.css' ] }) экспортный класс AppComponent {
result$: Observable<number>;
first$ = new Subject<number>();
second$ = new Subject<number>();
constructor() {}
ngOnInit(){
this.result$ = combineLatest(
this.first$,
this.second$
).pipe(
map(([first, second]) => {
console.info('combined obs emitted value');
return first + second;
})
);
// Solution 1: add timeout
setTimeout(() => {
console.info('first and second emit value');
this.first$.next(2);
this.second$.next(4);
})
}
ngAfterContentInit() {
console.info('ngAfterContentInit');
}
}
Порядок сейчас такой:
нгафтерконтентинит
первое и второе значение эмиссии
комбинированное значение излучения наблюдений
Итак, опять же, это потому, что подписка сделана до того, как наблюдаемые выдают значение?
Если я изменю observables на BehaviorSubject, все тоже будет работать, даже если значения выдаются до того, как произойдет подписка. Означает ли это, что BehaviourSubjects являются горячими наблюдаемыми? Компонент: работает
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
result$: Observable<number>;
first$ = new BehaviorSubject<number>(0);
second$ = new BehaviorSubject<number>(0);
constructor() {
}
ngOnInit(){
this.result$ = combineLatest(
this.first$,
this.second$
).pipe(
map(([first, second]) => {
// This is not printed to the console
console.info('combined obs emitted value');
return first + second;
})
);
console.info('first and second emit value');
this.first$.next(2);
this.second$.next(4);
}
ngAfterContentInit() {
console.info('ngAfterContentInit');
}
}





Q1: 2 наблюдаемых — это Субъекты, поэтому я предполагаю, что субъекты — это холодные наблюдаемые. Это правильно?
A1: ответ на этот вопрос говорит, что тема сама по себе горячая. Этот статья описывает горячие, холодные и предметы.
Q2: Итак, опять же, это потому, что подписка сделана до того, как наблюдаемые выдают значение?
А2: Да. Подписка на Subject получит значения ПОСЛЕ того, как вы подпишетесь. Введенная вами функция delay() должна была дать время для этого.
Почему? Это связано с тем, что BehaviorSubject всегда хранит значение и передает его при подписке, в то время как Subject не содержит значения, а просто передает значения от производителя текущим подписчикам. Подробности.
Q3: Означает ли это, что BehaviourSubjects являются горячими наблюдаемыми?
О: См. А1.
Извините, если это не отвечает на ваш вопрос напрямую. Я просто пытаюсь сказать, что... имея дело с Subject и BehaviorSubject, мне все равно, горячие они или холодные.
Вместо этого я спрашиваю: «Хочу ли я, чтобы наблюдаемые всегда сохраняли значение, когда я подписываюсь?». Если да, я использую BehaviorSubject. Если у меня все в порядке с отсутствием ценности при подписке, то Subject в порядке. Помимо этой разницы, оба они будут получать выпущенные значения после подписки. --- зависит от вашего варианта использования.
@AdrianBrand, если это правильно, почему выполнение this.result$ = this.first$ не обновляет шаблон?
потому что first$ уже сгенерирован и обновит шаблон только в том случае, если он будет сгенерирован после того, как он будет назначен свойству, за которым наблюдает асинхронный канал.
Используйте BehaviorSubjects вместо Subjects
https://stackblitz.com/edit/angular-4gnxto?file=src/app/app.component.ts
Асинхронный канал подписывается после отправки Субъектов. BehaviorSubjects дают самый последний результат, когда вы подписываетесь, Subjects дают вам значение только тогда, когда они испускают.
Когда асинхронный канал подписывается на наблюдаемый результат $, созданный с помощью combLatest, он не будет выдавать никакого значения от объектов, которые уже были отправлены, он будет использовать combLatest только для субъектов, которые отправляются после создания подписки.
Посмотрите, как в этом StackBtitz
https://stackblitz.com/edit/angular-eb7dge?file=src/app/app.component.ts
Если вы нажмете кнопку «Emit», значения будут отправлены после того, как асинхронный канал сделал подписку.
Субъекты горячие, но любые производные наблюдаемые с оператором канала, такие как this result$ observable, холодные и ничего не делают, пока на них не подписаны.