首页 > 解决方案 > 如果省略了防御性编码/错误检查,则 Angular Observable 订阅失败

问题描述

我正在使用带有 SignalR 的 Angular 8。我正在将一个可观察对象从我的 NotificationService 推送到 DashboardComponent。对于测试,我每 10 秒发送一条测试消息。

如果我在订阅处理程序中省略了一些防御性编码,订阅就会失败——即使实际的通知消息以正确的格式通过,所以在技术上不应该需要它。此外,我从订阅处理程序中收到一条一次性错误消息,该消息似乎在注册订阅时被执行(使用空对象 {})。可能最好用代码解释:

可观察的: (NotificationListenerService)

 private doorMessageSource: BehaviorSubject<any> = new BehaviorSubject<any>({});
  doorMessage$: Observable<any> = this.doorMessageSource.asObservable();

提升者: (NotificationListenerService)

this.doorMessageSource.next(notificationMessage);

订阅:( 仪表板组件)

constructor(private breakpointObserver: BreakpointObserver, private _router: Router, private _notificationListener: NotificationListenerService) {
    this.doorSubscription = this._notificationListener.doorMessage$
      .subscribe((notificationMessage) => {
        this.handleDoorMessage(notificationMessage);
      });
  }

处理程序:(订阅失败 - 没有处理后续事件) (仪表板组件)

  doorSubscription: Subscription;
  private handleDoorMessage(notificationMessage): void {
    // Note - This line does not fail even when notificationMessage = {}
    var message = notificationMessage.PayloadMessage;
    var messageId = notificationMessage.MessageId;

    // This line throws a one-off error message on subscription because 
    // notificationMessage = {} so message = undefined
    console.log(message.Timestamp + ' handleDoorMessage: ' + message.Name);

  }

处理程序:(工作) (仪表板组件)

  doorSubscription: Subscription;
  private handleDoorMessage(notificationMessage): void {
    var message = notificationMessage.PayloadMessage;
    var messageId = notificationMessage.MessageId;
    if (message) {
      // Executes correctly for my test messages every 10 seconds
      console.log(message.Timestamp + ' handleDoorMessage: ' + message.Name);
    } else {
      // Executes once 
      console.log('handleDoorMessage ERROR: Message Format Invalid');
    }
  }

所以,我真的只是想知道这里发生了什么?为什么在注册时使用空对象调用我的订阅处理程序?它是一个错误吗?还有其他人经历过吗?

标签: angularobservable

解决方案


发生这种情况是因为BehaviorSubject. BehaviorSubject当订阅者订阅BehaviorSubject. 实例化时BehaviorSubject,必须指定初始值。在您的情况下,它是一个空对象(即{})。

由于这个原因,您会看到记录了一次性消息。

如果您不希望这种行为,您可以使用Subjectwhich doesn't remember [它也不想在实例化时具有初始值] 最后发出的值。话虽如此,订阅者将仅接收在订阅实例之后发出的那些值Subject

还有一次,可观察管道中发生了异常,可观察对象将处于错误状态,并且无法发出新值。请参阅以下链接:https ://blog.angular-university.io/rxjs-error-handling/

希望能帮助到你。


推荐阅读