0

我有一个定义公共的 Angular 服务Subject。稍后在某些情况下,服务将调用.next()此主题。

另外,我有一个 Angular 组件,它在它的方法中.subscribe()对这个 Subject 进行调用,并在它的方法ngOnInit()中调用。.unsubscribe()ngOnDestroy()

虽然服务和组件都还活着,但我的代码工作正常。但是,用户可以在我的应用程序中单击不同的选项卡。这导致我的组件卸载并调用其ngOnDestroy()方法,这意味着 Observable 已取消订阅。

从这一点开始,组件不再存在,但服务仍然存在 - 其他组件仍在使用它。当.next()组件调用后服务调用方法时.unsubscribe(),抛出此错误ObjectUnsubscribedErrorERROR Error: Uncaught (in promise): ObjectUnsubscribedError: object unsubscribed

此外,稍后如果用户返回到包含该组件的选项卡,ngOnInit()则会执行 并且重新订阅此 observable 会再次引发相同的错误。

我做错了什么,我该如何解决这些错误?

import { Subject } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class StatusService {
  public statusChange$: Subject<number>;

  public constructor(...) {
    this.statusChange$ = new Subject<number>();
  }

  public someInternalLogic(someNumber: number): void {
    this.statusChange$.next(someNumber);
    // this will throw an error if StatusComponent call .unsubscribe()
  }
}

@Component({
  selector: 'app-status',
  templateUrl: './status.component.html',
  styleUrls: ['./status.component.scss']
})
export class StatusComponent implements OnInit, OnDestroy {
  public constructor(
    private _statusService: StatusService) {}

    public ngOnInit(): void {
      this._statusService.statusChange$.subscribe(value => this._onStatusChange(value));
  }

  public ngOnDestroy(): void {
    this._statusService.statusChange$.unsubscribe();
    // after this point if the StatusService calling .next() an error will be thrown
  }

  private _onStatusChange(value: number): void {
    // ....
  }
}

4

2 回答 2

1

另一种集体取消订阅 OnDestroy 事件的方法是使用 takeUntil 运算符。因此,您不必存储每个订阅,而是可以创建一个主题并在组件被销毁时触发它。

想象一下,您的服务有多个主题,并且您的组件订阅了每个主题。在这种情况下,您必须通过类属性(或一系列订阅)存储您的所有订阅,并且您必须手动取消订阅每个订阅。

class myComponent {

  // create any subject which allows you to push into
  // when your component gets destroyed
  private onDestroy = new Subject<void>();

  public ngOnInit(): void {
    // Subscription #1
    this._statusService.statusChange_1$.pipe(
      tap(() => /* do something */),
      // takeUntil will listen to changes of the onDestroy subject
      // and whenever you trigger it by this.onDestroy.next() it will
      // automatically unsubsribe for you
      takeUntil(this.onDestroy)
    ).subscribe();

    // Subscription #2
    this._statusService.statusChange_2$.pipe(
      takeUntil(this.onDestroy)
    ).subscribe(value => {
      /* do something else */
      // you can put your logic into your subscribe method as well
      // like you did in your question
    });

    // Any number of more subscriptions...
    // ...
  }

  public ngOndestroy(): void {
    // Notify the observers to unsibscribe
    this.onDestroy.next();
  }
}

这种方法适用于任何可观察的。

于 2022-02-06T18:13:59.100 回答
1

您不需要在组件中取消订阅服务主题。而是在组件中为服务主题创建订阅变量,并在组件销毁时取消订阅

subscription!: Subscription;

public ngOnInit(): void {
    this.subscription = this._statusService.statusChange$.subscribe(value => this._onStatusChange(value));
}

public ngOnDestroy(): void {
    this.subscription.unsubscribe();
}

private _onStatusChange(value: number): void {
    // ....
}
于 2022-02-06T17:27:52.287 回答