为什么组合的可观察对象在使用 Subject 时不更新模板,或者如果它们在 ngAfterContentInit 之后发出
Why do combined observables do not update template when using Subject or if they emit after ngAfterContentInit
我在组件中定义了一个可观察对象 (result$),并通过异步管道将其显示在其模板上。 observable 是其他 2 个 observables(first$,second$)通过 combineLatest 的组合。
如果一个或两个可观察对象发射得太早(在我发现的 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.log('combined obs emitted value');
return first + second;
})
);
console.log('first and second emit value');
this.first$.next(2);
this.second$.next(4);
}
ngAfterContentInit() {
console.log('ngAfterContentInit');
}
}
执行顺序为:
1.first 和第二个发射值
2.ngAfterContentInit
我这里的假设是,在 ngAfterViewInit 中,模板已经呈现并且已经进行了订阅。因为可观察对象在此之前发出一个值,所以不会通知组件。这只能意味着生成的可观察对象是冷的(因此,您需要在它发出值之前订阅)。 2个可观察对象是主题,所以我的假设是主题是冷可观察对象。这是正确的吗?
如果我延迟发出 first$ 和 second$,一切正常:
组件:first$ 和 second$ 稍后发出
@零件({
选择器:'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
导出 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]) => {
console.log('combined obs emitted value');
return first + second;
})
);
// Solution 1: add timeout
setTimeout(() => {
console.log('first and second emit value');
this.first$.next(2);
this.second$.next(4);
})
}
ngAfterContentInit() {
console.log('ngAfterContentInit');
}
}
现在的订单是:
ngAfterContentInit
第一个和第二个发射值
组合 obs 发射值
再说一次,这是因为订阅是在可观察对象发出值之前进行的吗?
如果我将可观察对象更改为 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.log('combined obs emitted value');
return first + second;
})
);
console.log('first and second emit value');
this.first$.next(2);
this.second$.next(4);
}
ngAfterContentInit() {
console.log('ngAfterContentInit');
}
}
Q1:2个可观察对象是主体,所以我的假设是主体是冷可观察对象。这是正确的吗?
A1:answer from this question says that the subject itself is hot. This article描述了热、冷和主题。
Q2:再说一次,这是因为订阅是在 observables 发出值之前进行的吗?
A2:是的。订阅 Subject 将在您订阅后收到值。您引入的 delay() 应该为这种情况的发生提供了时间。
为什么? 这是因为 BehaviorSubject
总是保存一个值并在订阅时发出它,而 Subject
不保存值,它只是从生产者向当前订阅者发出值。 .
Q3:这是否意味着 BehaviourSubjects 是热观察对象?
答:见A1。
如果这不能直接回答您的问题,我们深表歉意。我只是想说...在处理 Subject 和 BehaviorSubject 时,我并不关心它们是热的还是冷的。
相反,我问:"Do I want the observable to always hold a value when I subscribe?"。如果是,我使用 BehaviorSubject
。如果我没问题,订阅时没有任何价值,那么 Subject
就可以。除了这个区别,它们都将在订阅后收到发出的值。 --- 取决于您的用例。
使用 BehaviorSubjects 而不是 Subjects
https://stackblitz.com/edit/angular-4gnxto?file=src/app/app.component.ts
异步管道在主题发出后进行订阅。 BehaviorSubjects 在您订阅时给出最新结果,Subjects 只在它们发出时给您一个值。
当异步管道订阅使用 combineLatest 生成的 result$ observable 时,它不会从已经发出的 Subjects 发出任何值,它只会为订阅后发出的 Subjects 发出 combineLatest。
看看这个 StackBtitz
https://stackblitz.com/edit/angular-eb7dge?file=src/app/app.component.ts
如果您单击发出,则在异步管道进行订阅后发出值。
我在组件中定义了一个可观察对象 (result$),并通过异步管道将其显示在其模板上。 observable 是其他 2 个 observables(first$,second$)通过 combineLatest 的组合。 如果一个或两个可观察对象发射得太早(在我发现的 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.log('combined obs emitted value');
return first + second;
})
);
console.log('first and second emit value');
this.first$.next(2);
this.second$.next(4);
}
ngAfterContentInit() {
console.log('ngAfterContentInit');
}
}
执行顺序为:
1.first 和第二个发射值
2.ngAfterContentInit
我这里的假设是,在 ngAfterViewInit 中,模板已经呈现并且已经进行了订阅。因为可观察对象在此之前发出一个值,所以不会通知组件。这只能意味着生成的可观察对象是冷的(因此,您需要在它发出值之前订阅)。 2个可观察对象是主题,所以我的假设是主题是冷可观察对象。这是正确的吗?
如果我延迟发出 first$ 和 second$,一切正常: 组件:first$ 和 second$ 稍后发出 @零件({ 选择器:'my-app', templateUrl: './app.component.html', styleUrls: [ './app.component.css' ] }) 导出 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]) => {
console.log('combined obs emitted value');
return first + second;
})
);
// Solution 1: add timeout
setTimeout(() => {
console.log('first and second emit value');
this.first$.next(2);
this.second$.next(4);
})
}
ngAfterContentInit() {
console.log('ngAfterContentInit');
}
}
现在的订单是:
ngAfterContentInit
第一个和第二个发射值
组合 obs 发射值
再说一次,这是因为订阅是在可观察对象发出值之前进行的吗?
如果我将可观察对象更改为 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.log('combined obs emitted value');
return first + second;
})
);
console.log('first and second emit value');
this.first$.next(2);
this.second$.next(4);
}
ngAfterContentInit() {
console.log('ngAfterContentInit');
}
}
Q1:2个可观察对象是主体,所以我的假设是主体是冷可观察对象。这是正确的吗?
A1:answer from this question says that the subject itself is hot. This article描述了热、冷和主题。
Q2:再说一次,这是因为订阅是在 observables 发出值之前进行的吗?
A2:是的。订阅 Subject 将在您订阅后收到值。您引入的 delay() 应该为这种情况的发生提供了时间。
为什么? 这是因为 BehaviorSubject
总是保存一个值并在订阅时发出它,而 Subject
不保存值,它只是从生产者向当前订阅者发出值。
Q3:这是否意味着 BehaviourSubjects 是热观察对象?
答:见A1。
如果这不能直接回答您的问题,我们深表歉意。我只是想说...在处理 Subject 和 BehaviorSubject 时,我并不关心它们是热的还是冷的。
相反,我问:"Do I want the observable to always hold a value when I subscribe?"。如果是,我使用 BehaviorSubject
。如果我没问题,订阅时没有任何价值,那么 Subject
就可以。除了这个区别,它们都将在订阅后收到发出的值。 --- 取决于您的用例。
使用 BehaviorSubjects 而不是 Subjects
https://stackblitz.com/edit/angular-4gnxto?file=src/app/app.component.ts
异步管道在主题发出后进行订阅。 BehaviorSubjects 在您订阅时给出最新结果,Subjects 只在它们发出时给您一个值。
当异步管道订阅使用 combineLatest 生成的 result$ observable 时,它不会从已经发出的 Subjects 发出任何值,它只会为订阅后发出的 Subjects 发出 combineLatest。
看看这个 StackBtitz
https://stackblitz.com/edit/angular-eb7dge?file=src/app/app.component.ts
如果您单击发出,则在异步管道进行订阅后发出值。