angular - 为什么组合的可观察对象在使用主题时不更新模板,或者它们在 ngAfterContentInit 之后发出
问题描述
我在一个组件中定义了一个 observable (result$),并通过异步管道将它显示在它的模板上。observable 是其他 2 个 observables (first$, second$) 通过 combineLatest 的组合。如果其中一个或两个 observable 发出得太早(在我找到 ngAfterContentInit 之前),则生成的 observable 不会发出值。
组件:不起作用
@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 和 second 发射值
2.ngAfterContentInit
我在这里的假设是,在 ngAfterViewInit 中,模板已经被渲染并且订阅已经完成。因为可观察对象在此之前发出一个值,所以不会通知组件。这只能意味着生成的 observable 是冷的(因此,您需要在它发出值之前订阅)。2 个 observables 是 Subjects,所以我的假设是,subjects 是冷的 observables。这个对吗?
如果我延迟 first$ 和 second$ 的发射,一切正常: Component: first$ 和 second$ 稍后发射 @Component({ selector: 'my-app', templateUrl: './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.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 发射值
再说一遍,这是因为订阅是在可观察对象发出值之前进行的吗?
如果我将 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.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 个 observables 是 Subjects,所以我的假设是 subject 是冷 observables。这个对吗?
A1:这个问题的答案是主题本身很热门。这篇文章描述了热、冷和主题。
Q2:同样,这是因为订阅是在可观察对象发出值之前进行的吗?
A2:是的。订阅主题将在您订阅后收到值。您介绍的 delay() 应该有时间让这种情况发生。
为什么?这是因为 aBehaviorSubject
始终保存一个值并在订阅时发出它,而 aSubject
不保存一个值,它只是将值从生产者发送到当前订阅者。详情。
Q3:这是否意味着 BehaviourSubjects 是热门的 observables?
答:见 A1。
如果这不能直接回答您的问题,我们深表歉意。我只是想说......在处理主题和行为主题时,我真的不在乎它们是热的还是冷的。
相反,我问:“我是否希望 observable 在我订阅时始终保持一个值?”。如果是,我使用BehaviorSubject
. 如果我在订阅时没有任何价值就可以了,那就可以了Subject
。除了这个差异之外,它们都将在订阅后收到发出的值。--- 取决于您的用例。
推荐阅读
- python - 如何使用包含列表的内容通过 Python 自动发送电子邮件?
- node.js - 如何在 Node 和 Elm 应用程序(Heroku)中启用 URL 路由?
- c++ - C/C++ 中基的二进制变化
- .net - Resharper 损坏的参考 Visual Studio 2019 .Net Framework
- security - 从 SNMP 探测变量中检索数据
- node.js - 我怎样才能让http调用保持一段时间?
- python-3.x - 几天以来一直在苦苦挣扎,这个“继续”语句如何留下“a”并打印其余的信
- python-3.x - Drop NaN values but not the entire column
- python - Docker运行python脚本找不到本地安装的模块
- list - How can i iterate a list in elixir to make another list?