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

How to use switchmap to avoid nested subscriptions in Angular?

我阅读了很多关于 switchmap 及其用途的内容,但是在订阅新数据时我没有看到很多示例。 所以我在我的 Angular 项目中使用了嵌套订阅,我想问你如何在我的示例中正确使用 switchmap 以更好地理解这个概念。

这是我的嵌套订阅:

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;
            }
        })
})

这里如何正确使用switchmap? 感谢任何帮助。

这里有很多事情需要注意

  1. 看起来外部可观察对象 this.sharedSrv.postDetailthis.userSrv.getUserAsObservable() 是不相关的。在这种情况下,您还可以使用 RxJS forkJoin 并行触发可观察对象。由于您要求 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. 我假设您正在使用 async 将 observable 转换为 promise。首先,除非绝对必要,否则我建议您不要混合使用 observables 和 promises。其次,您可以使用 RxJS from 函数将 observable 转换为 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 => {
    ...
  }
);

看起来像你想要的:

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"];
  })
);

要转换 Observables,您需要使用 piping 即在可观察对象上调用 pipe() 方法并传入 rxjs 转换运算符

我们可以将您的代码转换为的示例


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()