Angular8:行为主体在提取到另一个服务时部分不起作用



我遇到了一个非常奇怪的问题:在我的应用程序中,我遵循了让状态服务处理所有状态的原则。随着应用程序的增长,我决定创建次状态服务。我将所有相关功能提取到专用服务中。其中,这部分从state.service.ts移动到bubble03-state.service.ts

@Injectable({
providedIn: 'root'
})
export class Bubble03StateService {
constructor() { }
/* tslint:disable:rule1 member-ordering */ 
// ...
public currentVisibleEFSubcontainer$ = new BehaviorSubject<string>('');
private currentSubjectValue = '';
updateCurrentVisibleEFSubcontainer(newVisibleContainer: string): void {
console.log(`updating with value ${newVisibleContainer}`);
if (newVisibleContainer !== this.currentSubjectValue) {
this.currentVisibleEFSubcontainer$.next(newVisibleContainer);
this.currentSubjectValue = newVisibleContainer;
} else {
this.currentVisibleEFSubcontainer$.next('');
this.currentSubjectValue = '';
}
}
}

方法updateCurrentVisibleEFSubcontainer()从两个位置调用,一个是组件,一个是另一个服务。现在奇怪的部分是:一旦我将此代码移动到新的次状态服务,只有一个调用触发订阅,而另一个调用不会。我真的无法解释为什么,因为它是完全相同的代码,只是在另一个地方。所有其他移动函数都可以正常工作。以下两个调用:

在组件中

onClickRowElement(): void {
if (this.rowElementAmount > 0) {
this.bubble03State.updateCurrentVisibleEFSubcontainer(this.rowElementTitle);
this.rowElementClicked.emit(this.rowElementTitle);
}
}

在另一个服务中

chart.options.data[0].click = (e) => {
this.explodePie(e);
this.bubble03State.updateCurrentVisibleEFSubcontainer(e.dataPoint.name);
};

订阅

this.bubble03State.currentVisibleEFSubcontainer$.subscribe(
newVisibleEFContainer => {
this.handleExpandableSubContainer(newVisibleEFContainer);
console.log(`newly visible ${newVisibleEFContainer}`);
}
);

如果从组件调用该方法几次,则会记录以下输出

> updating with value Kontoführung 
> newly visible Kontoführung updating
> with value Versand & Bearbeitung 
> newly visible Versand & Bearbeitung
> updating with value Versand & Bearbeitung 
> newly visible

但是,从服务调用方法会导致以下日志

> updating with value Kontoführung
> updating with value Versand & Bearbeitung
> updating with value Buchungsgebühren

一旦我将该方法及其相应的行为主体放回主服务中,一切都按预期工作。什么可能导致这种行为?除了名称外,国家服务之间没有区别。两者都在根目录中提供。

编辑:

为澄清起见,发布问题的最初情况如下:

  • StateService位于CoreModule,并于root提供。CoreModule仅在AppModule中导入。
  • Bubble03StateService位于延迟加载模块中,也以root提供。
  • Bubble03StateService用于延迟加载模块和第三个服务,该服务也位于CoreModule中并在root中提供,而StateService用于每个模块。

按照理查德·邓恩的建议,我重新安置了Bubble03StateService并尝试了一些事情。它现在也位于CoreModule

  • 当我删除provideIn: 'root'并将两个服务都放在AppModuleproviders数组中时,常规StateService仍然可以正常工作,但Bubble03StateService抛出NullInjectorError: no providers for...
  • 重新插入provideIn: 'root'并从AppModule中删除,服务已加载,但是发生了一些我不明白的事情:在服务的构造函数中,我创建一个随机数,并在调用服务函数时记录它。当将BehaviourSubject及其相应的更新方法放在StateService中时,无论谁调用该方法(第三个服务和延迟加载组件(,随机数总是相同的。但是当我把它放回Bubble03StateService(此时它在所有方面都与StateService相同,除了它的名字(,从第三个服务和延迟加载的组件调用时,随机数是不同的。这让我更加困惑,因为现在CoreModule的所有三项服务都应该是单例。如果不是,为什么StateService是单例,而Bubble03StateService不是,当它们以相同的方式声明、提供和定位时?

可能是 Angular 8 的模块延迟加载导致了这个问题。具体而言,如果使用依赖关系注入的@Injectable({ providedIn: 'root' })方法,则可能会创建单一实例服务,具体取决于订阅者父模块与根模块的关系。

您应该删除此方法并使用:@NgModule({ providers: [Bubble03StateService] })在您的根模块中。这将保证它是单例服务。

我终于找到了问题的原因。

不知何故,在另一个服务中自动导入服务时,自动导入函数将扩展.js添加到 import 语句中。这真的很难抓住,因为它不是你通常会明确检查的东西。

虽然这个位置甚至没有.js文件,但 Angular 以某种方式理解了这一点,并从.ts-File 导入正确的类/服务/组件等。但它创建了服务的新实例,消除了单例原则。

因此,最后,从导入中删除.js扩展是必须完成的。

最新更新