Angular OnInit和异步管道之间的计时问题
我对Angular OnInit和异步管道之间的计时问题,angular,rxjs,async-pipe,Angular,Rxjs,Async Pipe,我对async-管道与Observable组合有问题,后者在OnInit中获取它的第一个值。必须是关于OnInit发生的时间点,以及模板被呈现,从而可观察的被订阅的时间点的时间问题 考虑这一部分: 导出类AppComponent实现OnInit{ 主题A$:主题; 主题B$:主题; 建造师( 受保护的http:HttpClient ) { } 恩戈尼尼特(){ this.subjectA$=新主题(); this.subjectA$.next({name:“A”}); this.subjectB
async
-管道与Observable
组合有问题,后者在OnInit
中获取它的第一个值。必须是关于OnInit
发生的时间点,以及模板被呈现,从而可观察的
被订阅的时间点的时间问题
考虑这一部分:
导出类AppComponent实现OnInit{
主题A$:主题;
主题B$:主题;
建造师(
受保护的http:HttpClient
) {
}
恩戈尼尼特(){
this.subjectA$=新主题();
this.subjectA$.next({name:“A”});
this.subjectB$=新主题();
设置超时(()=>{
this.subjectB$.next({name:“B”});
}, 0);
}
}
以及模板:
subjectA:{{subjectA.name}
无主语
subjectB:{{subjectB.name}
无主题B
这导致
no subjectA
subjectB: B
这意味着:即使subjectA$
在onInit
中获得了一个值,视图也不会更新。如果我在setTimeout
中创建第一个值,正如您在subjectB$
中看到的那样,它会工作,我会看到值。虽然这是一个解决方案,但我想知道为什么会发生这种情况,还有更好的解决方案吗?
我已经找到的一个解决方案是使用BehaviorSubject
而不是提供第一个值作为初始值:
this.subjectC$=新的行为主体({name:“C”});
使用subjectC的类似模板引导到subjectC:C
我真正的可观察对象根本不是主题
,而是不同内容的组合相关测试
-调用的结果,从中只有一个是主题
(不幸的是,因为它使用的是@Input()
-注释中的值),并使用OnInit
中的next
手动按下,如示例所示。其余部分来自http
等。很可能我可以将组合结果包装成behavior subject
,但对我来说,它看起来丑陋而危险,因此比setTimeout
方法更糟糕。但我打赌有人能帮我找到一个真正有用的解决办法。
此外,我更愿意避免行为主体
,以防止开发人员尝试使用getValue
一个快速修复方法是与缓冲区1一起使用,而不是与
行为主体一起使用。您不必提供默认值,它既没有getValue()
函数,也没有value
getter。但它缓冲(或保存)最后发出的值,并在新订阅时立即发出
试试下面的方法
ngOnInit(){
this.subjectA$=新的ReplaySubject(1);
this.subjectA$.next({name:“A”});
this.subjectB$=新的ReplaySubject(1);
this.subjectB$.next({name:“B”});
this.subjectC$=CombineTest([this.subjectA$,this.subjectB$]).pipe(
映射((things:[{name:string},{name:string}]):{name:string}=>{
return{name:things.map(thing=>thing.name).join(“|”)}
})
);
}
我已经修改了您的。一个快速修复方法是使用buffer 1,而不是BehaviorSubject
。您不必提供默认值,它既没有getValue()
函数,也没有value
getter。但它缓冲(或保存)最后发出的值,并在新订阅时立即发出
试试下面的方法
ngOnInit(){
this.subjectA$=新的ReplaySubject(1);
this.subjectA$.next({name:“A”});
this.subjectB$=新的ReplaySubject(1);
this.subjectB$.next({name:“B”});
this.subjectC$=CombineTest([this.subjectA$,this.subjectB$]).pipe(
映射((things:[{name:string},{name:string}]):{name:string}=>{
return{name:things.map(thing=>thing.name).join(“|”)}
})
);
}
我已经修改了你的。在我发表评论之后,我真的忍不住想一定有更好的方法——最后想到了一些有效的方法
我只是稍微修改了一下你的stackblitz
private valueA = "A";
private valueB = "B";
subjectA$ = of({ name: this.valueA });
subjectB$ = of({ name: this.valueB });
subjectC$ = combineLatest([this.subjectA$, this.subjectB$])
.pipe(
map((things: [{name:string}, {name:string}]): {name:string} => {return {name: things.map(x => x.name).join('|')}})
);
这样,我们甚至可以放弃ngOnInit
hook,一切都应该在它上面运行 在我发表评论之后,我真的忍不住想一定有更好的办法——最后想到了一些行之有效的办法
我只是稍微修改了一下你的stackblitz
private valueA = "A";
private valueB = "B";
subjectA$ = of({ name: this.valueA });
subjectB$ = of({ name: this.valueB });
subjectC$ = combineLatest([this.subjectA$, this.subjectB$])
.pipe(
map((things: [{name:string}, {name:string}]): {name:string} => {return {name: things.map(x => x.name).join('|')}})
);
这样,我们甚至可以放弃ngOnInit
hook,一切都应该在它上面运行 最近有一个类似的问题(特别是将@输入转换为可观察的),我可以通过使用shareReplay(1)
(或者使用缓冲区为1的ReplaySubject
)来解决对于可观察对象-do.next insidengOnInit
的问题似乎是它在模板实际订阅可观察对象之前先运行。将内容移动到ngAfterViewInit(或ngAfterContentInit)并不能真正解决问题,因为更改检测会抱怨。因此,我剩下的就是重放最后一个值,将其存储在行为子对象中,或者也使用设置超时值。。。互联网上怎么会充斥着使用async
而不是手动订阅的建议,但却没有一个合适的解决方案呢?最近有一个类似的问题(特别是将@Input转换为observatable),我可以通过使用shareReplay(1)
(或者使用缓冲区为1的ReplaySubject
)来解决对于可观察对象-do.next insidengOnInit
的问题似乎是它在模板实际订阅可观察对象之前先运行。将内容移动到视图中