我是RxJS的新手,我想学习如何以干净的方式使用它编写代码。我已经嵌套了订阅,并且尝试重写它,但是没有结果。
firstMethod() {
this.testMethod(name)
console.log(this.currentPerson)
}
testMethod() {
this.myService.search(name).subscribe(response => {
if(result) {
this.currentPerson = result
} else {
this.myService.create(name).subscribe(result => {
const person = {id: result.id, name: name}
this.currentPerson = person
})
}
})
}
不幸的是,尽管代码很混乱,但在“ else”之后的某些部分还是有问题,因为console.log显示未定义。 有提示如何解决吗?
答案 0 :(得分:3)
要有效地处理嵌套订阅,您应该使用“ Higher Order Mapping Operator”之一,它可以为您带来一些好处:
在这种情况下,switchMap
是一个不错的选择,因为它一次只允许一个内部订阅,因此,每当调用myService.search(name)
时,都会为myService.create(name)
创建一个新的内部订阅,而前一个将自动取消订阅。
@Rafi Henig的答案很好地说明了这种情况。
.pipe()
。您可以使用管道运算符定义对可观察输出的转换,而无需实际订阅。我建议您不要订阅testMethod()
,而是返回一个可观察的结果。另外,让我们给“ testMethod()”一个更有意义的名称以供进一步讨论:“ getPerson()”。
getPerson(name: string): Observable<Person> {
return this.myService.search(name).pipe(
switchMap(result => {
return iif(
() => result,
of(result),
this.myService.create(name).pipe(
map(({ id }) => ({ id, name }))
)
)
}),
tap(person => this.currentPerson = person)
);
}
console.log显示未定义。有提示如何解决吗?
1 firstMethod() {
2 this.getPerson(name)
3 console.log(this.currentPerson)
4 }
使用undefined
的原因是因为代码是异步的。先执行第2行,然后执行第3行,但异步工作尚未完成,因此尚未设置this.currentPerson
。
由于我们的getPerson()
方法现在返回了一个可观察值,因此我们可以订阅并在订阅中执行您的console.log()
:
1 firstMethod() {
2 this.getPerson(name).subscribe(
3 () => console.log(this.currentPerson)
4 )
5 }
为简化起见,我们甚至不再需要this.currentPerson
,因为此人是通过流发出的!
1 firstMethod() {
2 this.getPerson(name).subscribe(
3 person => console.log(person)
4 )
5 }
既然你想...
学习如何以简洁的方式编写代码
我认为最干净的方法可能是将“人员结果”定义为可观察到的this.currentPerson
。
person$ = this.getPerson(name);
所以现在您有this.person$
可以订阅,并且将始终具有person的当前值。无需“手动”更新this.currentPerson
。
好吧...差不多。我们需要考虑一下搜索词发生变化时会发生什么情况。
我们假设搜索词“名称”来自表单控件输入。
使用Reactive Forms时,输入值是一个可观察的来源,因此我们可以从搜索词中定义person$
:
searchTerm$ = this.searchInput.valueChanges();
person$ = this.searchTerm$.pipe(
switchMap(searchTerm => this.getPerson(searchTerm))
);
getPerson(name: string): Observable<Person> {
return this.myService.search(name).pipe(
switchMap(result => {
return iif(
() => result,
of(result),
this.myService.create(name).pipe(
map(({ id }) => ({ id, name }))
)
)
})
);
}
注意,我们已经定义了两个不同的可观察对象,但是我们还没有订阅!现在,我们可以利用模板中的async
管道来处理订阅,从而使我们的组件代码简洁明了。
<p *ngIf="person$ | async as person">
We found {{ person.name }} !
</p>
我知道这已经花了很长的时间了,但是我希望您能看到使用管道运算符转换输出的可能性,以及如何定义另一个可观察变量。
答案 1 :(得分:2)
使用switchMap使用IIF operator根据result
的值返回一个新的Observable,如下所示:
this.myService.search(name)
.pipe(
switchMap(result => {
return iif(
() => result,
of(result),
this.myService.create(name).pipe(map(({ id }) => ({ id, name })))
)
})
)
.subscribe(person => {
})
或可选:
this.myService.search(name)
.pipe(
switchMap(result => {
if (result) return of(result);
else this.myService.create(name).pipe(map(({ id }) => ({ id, name })));
})
)
.subscribe(person => {
})