admin管理员组文章数量:1406312
I am new with RxJS and I want to learn how to write code using it in clean way. I have nested subscription and I' ve tried to rewrite this, but with no result.
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
})
}
})
}
Unfortunatelly despite the code is messy, there is something wrong with some piece after 'else' because console.log shows undefined. Any tips how to fix it?
I am new with RxJS and I want to learn how to write code using it in clean way. I have nested subscription and I' ve tried to rewrite this, but with no result.
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
})
}
})
}
Unfortunatelly despite the code is messy, there is something wrong with some piece after 'else' because console.log shows undefined. Any tips how to fix it?
Share Improve this question asked Sep 2, 2020 at 18:11 tigertiger 1172 silver badges10 bronze badges 1- check switchMap – robert Commented Sep 2, 2020 at 18:15
2 Answers
Reset to default 4To effectively handle nested subscribes, you should use one of the "Higher Order Mapping Operator", which do a few nice things for you:
- maps the ining value to another observable
- subscribes to it, so its values are emitted into the stream
- manages unsubscribing from these "inner subscriptions" automatically
In this case, switchMap
is a good choice because it will only allow a single inner subscription at a time, so whenever myService.search(name)
is called a new inner subscription for myService.create(name)
is created, and the previous one is automatically unsubscribed.
@Rafi Henig's answer shows a good example of what this could look like.
- Notice the use of
.pipe()
. You can define transformations to your observable output using pipeable operators without actually subscribing.
I would suggest you don't subscribe in your testMethod()
, but rather return an observable. Also, let's give "testMethod()" a more meaningful name for further discussion: "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 shows undefined. Any tips how to fix it?
1 firstMethod() {
2 this.getPerson(name)
3 console.log(this.currentPerson)
4 }
The reason for the undefined
is because the code is asynchronous. Line 2 is executed, then line 3 immediately after, but the async work hasn't been finished yet, so this.currentPerson
hasn't been set yet.
since our getPerson()
method now returns an observable, we can subscribe and do your console.log()
inside the subscribe:
1 firstMethod() {
2 this.getPerson(name).subscribe(
3 () => console.log(this.currentPerson)
4 )
5 }
To simplify, we don't even need this.currentPerson
anymore, because the person is emitted through the stream!
1 firstMethod() {
2 this.getPerson(name).subscribe(
3 person => console.log(person)
4 )
5 }
And since you want to...
learn how to write code using it in clean way
I think think cleanest way would probably be to define your "person result" as an observable and ditch this.currentPerson
.
person$ = this.getPerson(name);
So now you have this.person$
which can be subscribed to and will always have the current value of person. No need to "manually" update this.currentPerson
.
Well... almost. We need to consider what happens when the search term changes.
Let's assume the search term "name" is ing from a form control input.
When using Reactive Forms the input value is an observable source, so we can define our person$
from the search term:
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 }))
)
)
})
);
}
Notice we've defined two different observables, but we haven't subscribed yet! Now, we can leverage the async
pipe in our template to handle the subscription, keeping our ponent code nice and simple.
<p *ngIf="person$ | async as person">
We found {{ person.name }} !
</p>
I know this has gotten a bit long winded, but I hope you see how its possible to transform output using pipeable operators and how you can define one observable from another.
Use switchMap to return a new Observable based of the the value of result
using IIF operator as demonstrated below:
this.myService.search(name)
.pipe(
switchMap(result => {
return iif(
() => result,
of(result),
this.myService.create(name).pipe(map(({ id }) => ({ id, name })))
)
})
)
.subscribe(person => {
})
Or optionally:
this.myService.search(name)
.pipe(
switchMap(result => {
if (result) return of(result);
else this.myService.create(name).pipe(map(({ id }) => ({ id, name })));
})
)
.subscribe(person => {
})
本文标签: javascriptHow to write nested subscribe in cleaner wayStack Overflow
版权声明:本文标题:javascript - How to write nested subscribe in cleaner way? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745005204a2637219.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论