简体   繁体   English

Angular中如何使用switchmap避免嵌套订阅?

[英]How to use switchmap to avoid nested subscriptions in Angular?

I read a lot about switchmap and its purpose but I did not see a lot of examples when it comes to subscribing to the new data.我阅读了很多关于 switchmap 及其用途的文章,但在订阅新数据时我没有看到很多示例。 So I use a nested subscription in my Angular project and I wanted to ask you how to use switchmap properly in my example to understand the concept better.所以我在我的 Angular 项目中使用了嵌套订阅,我想问你如何在我的示例中正确使用 switchmap 以更好地理解这个概念。

Here my nested subscription:这是我的嵌套订阅:

this.sharedSrv.postDetail.subscribe(async post => {
        if(post) {
            this.hasPost = true;
            this.post = post;
        }
        console.log(post);
        this.viewedMainComment = null;
        this.viewedSubComments = [];
        this.userSrv.getUserAsObservable().subscribe(user => {
            if(user){
                if(this.post.user.id == user.id) this.isOwnPost = true; 
                this.user = user;
                this.postsSrv.getPostInteraction(this.user.id, this.post.id, this.post.user.id).subscribe(interaction => {
                    this.hasSubscribed = interaction["hasSubscribed"];
                    this.wasLiked = interaction["wasLiked"];
                    this.wasDisliked = interaction["wasDisliked"];
                    this.hasSaved = interaction["hasSaved"];
                });
                console.log(user);
                this.isLoggedIn = true
            } else {
                this.isLoggedIn = false;
            }
        })
})

How would I use switchmap correctly here?我将如何在这里正确使用 switchmap? Any help is appreciated.任何帮助表示赞赏。

There are multiple things to notice here这里有很多事情需要注意

  1. Looks like the outer observable this.sharedSrv.postDetail and this.userSrv.getUserAsObservable() are unrelated.看起来外部可观察this.sharedSrv.postDetailthis.userSrv.getUserAsObservable()是不相关的。 In that case you could also use RxJS forkJoin to trigger the observables in parallel.在这种情况下,您还可以使用 RxJS forkJoin并行触发可观察对象。 Since you've asked for switchMap , you could try the following由于您要求switchMap ,您可以尝试以下操作
import { of } from 'rxjs';
import { switchMap } from 'rxjs/operators';

this.sharedSrv.postDetail.pipe(
  switchMap(post => {
    if (post) {
      this.hasPost = true;
      this.post = post;
    }
    console.log(post);
    this.viewedMainComment = null;
    this.viewedSubComments = [];
    return this.userSrv.getUserAsObservable();
  }),
  switchMap(user => {
    if (user) {
      if (this.post.user.id == user.id) this.isOwnPost = true;
      this.user = user;
      console.log(user);
      return this.postsSrv.getPostInteraction(this.user.id, this.post.id, this.post.user.id);
    }
    return of(null); // <-- emit `null` if `user` is undefined
  })
).subscribe(
  interaction => {
    if(!!interaction) { // <-- only proceed if `interaction` is defined
      this.hasSubscribed = interaction["hasSubscribed"];
      this.wasLiked = interaction["wasLiked"];
      this.wasDisliked = interaction["wasDisliked"];
      this.hasSaved = interaction["hasSaved"];
      this.isLoggedIn = true;
    } else { // <-- set `isLoggedIn` to false if `user` was undefined
      this.isLoggedIn = false;
    }
  }
);
  1. I assume you're converting the observable to a promise using async .我假设您正在使用async将 observable 转换为 promise 。 First I'd recommend you not to mix observables and promises unless absolutely necessary.首先,除非绝对必要,否则我建议您不要混合使用 observables 和 promises。 Second you could use RxJS from function to convert an observable to a promise.其次,您可以使用 function from RxJS 将可观察值转换为 promise。
import { from, of } from 'rxjs';
import { switchMap } from 'rxjs/operators';

const obs$ = this.sharedSrv.postDetail.pipe(
  switchMap(post => {
    if (post) {
      this.hasPost = true;
      this.post = post;
    }
    console.log(post);
    this.viewedMainComment = null;
    this.viewedSubComments = [];
    return this.userSrv.getUserAsObservable();
  }),
  switchMap(user => {
    if (user) {
      if (this.post.user.id == user.id) this.isOwnPost = true;
      this.user = user;
      console.log(user);
      return this.postsSrv.getPostInteraction(this.user.id, this.post.id, this.post.user.id);
    }
    return of(null); // <-- emit `null` if `user` is undefined
  })
);

from(obs$).then(
  interaction => {
    ...
  }
);

Looks like what you want:看起来像你想要的:

this.sharedSrv.postDetail.pipe(
  switchMap(post => {
    if (post) {
      this.hasPost = true;
      this.post = post;
    }
    console.log(post);
    this.viewedMainComment = null;
    this.viewedSubComments = [];
    return this.userSrv.getUserAsObservable();
  }),
  swtichMap(user => {
    this.isLoggedIn = false;
    if (user) {
      if (this.post.user.id == user.id) this.isOwnPost = true;
      this.user = user;
      this.isLoggedIn = true;
      console.log(user);
      return this.postsSrv.getPostInteraction(this.user.id, this.post.id, this.post.user.id);
    } else {
      return of(null);
    }
  }).subscribe(interaction => {
    if (!interaction) return;
    this.hasSubscribed = interaction["hasSubscribed"];
    this.wasLiked = interaction["wasLiked"];
    this.wasDisliked = interaction["wasDisliked"];
    this.hasSaved = interaction["hasSaved"];
  })
);

To transform Observables you need to use piping ie call the pipe() method on the observable and pass in the an rxjs transformation operator要转换Observables ,您需要使用piping ,即在 observable 上调用pipe()方法并传入rxjs转换运算符

Example we can transform your code to我们可以将您的代码转换为的示例


this.sharedSrv.postDetail.pipe(
  switchMap(post => {
    if(post) {
      this.hasPost = true;
      this.post = post;
    }
    this.viewedMainComment = null;
    this.viewedSubComments = [];
    return this.userSrv.getUserAsObservable())
  }),
  switchMap(
    user => {
      if(user) {
         if(this.post.user.id == user.id) this.isOwnPost = true; 
         this.user = user;
         return this.postsSrv.getPostInteraction(this.user.id, this.post.id, this.post.user.id)
      } else {
        this.isLoggedIn = false;
        return of (null) // You need import { of } from 'rxjs'
      }
    }
  )), 
  tap( interaction => {
    if(interaction) {
      this.hasSubscribed = interaction["hasSubscribed"];
      this.wasLiked = interaction["wasLiked"];
      this.wasDisliked = interaction["wasDisliked"];
      this.hasSaved = interaction["hasSaved"];
    }
  })
  
).subscribe()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM