Angular:一种识别服务呼叫者

时间:2018-05-31 23:54:16

标签: javascript angular typescript

背景

具有嵌套组件和服务的复杂Angular特征模块。顶级组件订阅了要通知的主题,并通知模块内部捕获的错误。

问题:

所有顶级组件收到错误通知(因为他们订阅了subject.next消息)并做出反应

实施的解决方案:

通过'指纹进行过滤,但这需要在所有服务中使用.catch()连接的所有方法添加指纹'参数。

例如:

...
@Injectable()
export class SharedService {

    getSth (idOfWhatToGet: string, fingerprint: string) { // <<< !!! fignerprint
         this.http.get('myurl') 
            .toPromise()
            .then(a => a)
            .catch(err => this.subject.next({err, fingerprint}); // <<< !!!
}

顶级组件:

...
@Component({...}) 
export class SomeTopLevelComponent {

      @Output() onError = new EventEmitter<Error>();
      private myFingerprint = 'STL_component';
      ...
      this.subject.subscribe(errMsg => errMsg.fingerprint === 'myFingerprint ' ?
          this.onError = errMsg.err);           // <<< !!! fingerprint filtered
}
  

有没有办法辨别哪个组件称为服务?

如果不是,那么什么可能是最佳的解决方法,或者比将“指纹”更好?每个服务电话的参数?

更多详情

让我们假设一个Angular项目使用了一个功能UI模块,包括:

  • 2个顶级组件
  • 内部有10个可重复使用的组件
  • 5个共享服务,每个服务有3种方法(所有方法
    返回承诺)

通常使用feature-module-exposed-elements(顶级组件):

<my-angular-project> 
    <feature-el-1 (onError)="callErrHandler($event)></feature-el-1>
    <feature-el-2 (onError)="callErrHandler($event)></feature-el-2>
<my-angular-project>

feature-el-1和feature-el-2组件都订阅了传入的错误消息:

OnInit() {
   this.subjectSubscription = this.errorService.getErrorsMessages()
      .subscribe(errorMessage => this.onError.emit(errorMessage.err));
}

当发现错误时,所有服务都会发送错误:

...
doSth.then(p => ...)
    .catch(err => this.errorService.sendErrorMessage({err})

错误服务的实现类似于:

@Injectable()
export class errorService {
    private subject = new Subject<any>();

    sendErrorMessage(message: {err: Error}) {
        this.subject.next(message);
    }

    getErrorsMessages(): Observable<any> {
        return this.subject.asObservable();
    }
}

现在,<feature-el-1><feature-el-2>通过调用同一服务上的方法加载数据,让我们说getAddresses()。接下来会发生什么:从<feature-el-1>发起的呼叫成功,来自<feature-el-2>的呼叫失败。但是 BOTH <feature-el-1><feature-el-2>会收到错误并将onError事件提升(我们只想要其中一个,即 - 服务崩溃的那个,举起活动)。

要解决此问题,我们会使用&#39;指纹&#39; - 基于某些逻辑(指示下游哪个顶级组件发生错误)添加到每个服务方法调用的参数,以便暴露的顶级组件可以决定 - 是否提高接收到的错误消息。它是一个笨重而繁琐的逻辑代码体,所以所有这些都归结为主要问题 - 服务器是否可以知道(当它知道它可以传回这些知识时,比喻说)哪个组件称为他?

1 个答案:

答案 0 :(得分:0)

您有一个名为SharedService的服务,用于处理后端API的Http请求,并且您希望在顶级组件中侦听错误。您希望共享该服务,以便其他组件可以使用它,但您不希望共享错误。

您遇到的问题是服务何时发出错误,您不知道哪个顶级组件负责原始Http请求。

<my-angular-project> 
    <feature-el-1 (onError)="callErrHandler($event)></feature-el-1>
    <feature-el-2 (onError)="callErrHandler($event)></feature-el-2>
<my-angular-project>

在上面的例子中;您有两个名为feature-el-1feature-el-2的功能组件。每个组件只需要发出源自该组件或其中一个子组件的错​​误。

使用组件提供程序

SharedService providers数组中删除NgModule,并将其添加到每个功能组件的providers数组中。

@Component({
      selector: 'feature-el-1',
      providers: [SharedService],
      template: '<child-feature></child-feature>'
})
export class FeatureElOneComponent {
      @Output() onError: Observable<Error>;
      constructor(service: SharedService) {
           this.onError = service.errors;
      }
}

@Component({
      selector: 'feature-el-2',
      providers: [SharedService],
      template: '<child-feature></child-feature>'
})
export class FeatureElTwoComponent {
      @Output() onError: Observable<Error>;
      constructor(service: SharedService) {
           this.onError = service.errors;
      }
}

现在您为每个组件定义了providers: [SharedService],然后每个组件都会收到该服务的实例。他们不会共享相同的服务。

现在,让我们看一下<child-feature>组件。

@Component({
      selector: 'child-feature',
      template: '<span>Child Feature</span>'
})
export class ChildFeatureComponent {
      constructor(service: SharedService) {
           service.doSth().then((data)=>console.log(data));
      }
}

两个功能模块都使用此组件,但ChildFeatureComponent的每个实例都会收到SharedService的不同实例。因此,当FeatureElOneComponent内使用的子组件触发错误时,只有该功能组件才会收到错误。