首页 文章

在Angular 2中的rxjs中使用switchMap运算符时,我们是否必须取消订阅?

提问于
浏览
5

在Angular 2中,有一些您不需要取消订阅的可观察对象 . 例如http requests和activatedRoute.params .

Angular/RxJs When should I unsubscribe from Subscription

但是当我使用switchMap时会发生什么情况,例如activatedRoute.params,并且在switchMap内部我访问一个服务,该服务返回一个observable,如果以通常的方式订阅则需要取消订阅 .

像这样的东西:

this.activatedRoute.params
    .switchMap((params: Params) => this.userService.getUser(+params['id']))
    .subscribe((user: User) => this.user = user);

如果我在没有switchMap且没有activateRoute.params的情况下调用this.userService,我将不得不取消订阅 .

// userService.getUser() takes in optional id?: number.
this.subscription = this.userService.getUser().subscribe(
    (user: User) => {
        this.user = user;
    }
 );

然后......

this.subscription.unsubscribe();

我的问题是,如果我在其上使用switchMap并调用需要取消订阅的服务,是否需要取消订阅activatedRoute.params?

2 回答

  • 0

    如果您订阅的源可观察对象总是完成或错误,则无需取消订阅 .

    但是,如果使用 switchMap 从源编写另一个observable,则是否需要取消订阅取决于 switchMap 中返回的可观察量 . 如果返回的observable并不总是完成或错误,那么,是的,您需要取消订阅 .

    如果源错误,将自动取消订阅:

    const source = new Rx.Subject();
    const composed = source.switchMap(() => Rx.Observable.interval(200));
    
    composed.subscribe(value => console.log(value));
    source.next(1);
    
    setTimeout(() => {
      console.log("Erroring...");
      source.error(new Error("Boom!"));
    }, 1000);
    
    .as-console-wrapper { max-height: 100% !important; top: 0; }
    
    <script src="https://unpkg.com/rxjs@5.4.1/bundles/Rx.min.js"></script>
    

    但是,如果源完成,则不会发生自动取消订阅:

    const source = new Rx.Subject();
    const composed = source.switchMap(() => Rx.Observable.interval(200));
    
    composed.subscribe(value => console.log(value));
    source.next(1);
    
    setTimeout(() => {
      console.log("Completing...");
      source.complete();
    }, 1000);
    
    .as-console-wrapper { max-height: 100% !important; top: 0; }
    
    <script src="https://unpkg.com/rxjs@5.4.1/bundles/Rx.min.js"></script>
    
  • 8

    执行切换映射后,订阅将附加到最后一个Observable . 如果第一个观察者保持触发,则无关紧要 . switchmap块只执行一次 .

    如果永远不会关闭,你必须从最后一个取消订阅 .

    检查此代码:

    import { Component, OnInit } from '@angular/core';
    import { Observable, BehaviorSubject, Subscription} from 'rxjs';
    import * as Rx from 'rxjs';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent implements OnInit {
      title = 'app works!';
      private source: Rx.Subject<any>;
      private source2: Rx.Subject<any>;
      private composed: Rx.Observable<any>;
      private composedSub: Subscription;
    
      public ngOnInit(): void {
        this.source = new Rx.Subject();
        this.source2 = new Rx.Subject();
    
        this.composed = this.source.switchMap(value => this.source2);
    
        this.composedSub = this.composed.subscribe(value => console.log(value));
        console.log(this.composedSub);
      }
    
      private onClick() {
        // Triggers the first observable, the console.log is never executed.
        this.source.next(1);
      }
    
      private onClick2() {
        // Console.log is executed, prints "1"
        this.source2.next(1);
      }
    
      private onClick3() {
        // The console log is never called again after click on this button.
        this.composedSub.unsubscribe();
      }
    
      private onClick4() {
        // The first observable finish. the console log keeps printing unles onClick3 is executed
        this.source.complete();
      }
    
      private onClick5() {
        // console.log never executed egain.
        this.source2.complete();
      }
    }
    

相关问题