角度跨服务通信

时间:2017-07-07 16:36:04

标签: angular typescript rxjs angular-services

我有一个统计应用程序。在我的页面的左侧,我有主题列表,在顶部 - 组列表。主要部分包含与主题和组相关的统计项目。

此外,我还有几个服务为我的应用程序提供业务逻辑。为简单起见,我们先谈谈其中三个: ThemeSerivce,GroupService StatisticsService

最终用户可以操作主题和组列表(添加或删除项目),并且每次更改后都必须重新计算统计信息。在此应用程序中,我使用 rx.js 中的 Subjects Subsription 来跟踪此类更改。

所以,在我的组件中,我可以这样写:

GroupComponent

 removeGroup() {
        this.groupService.removeGroup(this.group);
        this.statisticsService.updateStatistics();
      }

for ThemeComponent

removeTheme() {
    this.themeService.removeTheme(this.theme);
    this.statisticsService.updateStatistics();
  }

但从逻辑上讲,这些组件不必了解统计数据。当然,我可以将 StatisticsService 的依赖关系移动到 ThemeService GroupService ,但是我必须调用 statisticsService.updateStatistics()< / em>在每个更改主题或组集合的方法中。这就是我希望通过订阅实现直接跨服务通信的原因。

最后我的问题:

  1. 这根本不是一个好主意吗?

  2. 如果没问题,实施它的最佳方法是什么? 当我在组件中使用订阅时,我在 ngOnInit()方法中注册它并取消订阅 ngOnDestroy()以防止内存泄漏。 我可以在服务的构造函数中订阅吗?我何时何地取消订阅?或者,当我在App模块级别注册我的服务作为提供者时,它可能没有必要吗?

1 个答案:

答案 0 :(得分:0)

StatisticsService应订阅主题和群组列表。您的个人组件应仅订阅其各自的服务(ThemeComponent to ThemeService,Group to Group etc)。

为简单起见,我只关注ThemeService,但GroupService类似。调用remove时,ThemeService应该有一个内部SubjectSubject下一个值(可能是整个新列表)。

StatisticsService将订阅ThemeService观察点并在更改后重新计算。它看起来像这样

/* theme.service.ts */
@Injectable()
export class ThemeService {
    private _list$ = new Subject<ThemeList>();

    get list(): Observable<ThemeList> {
        return this._list$.asObservable();
    }

    set list(newList: ThemeList) {
       this._list$.next(newList);
    }
}


/* statistics.service.ts */
@Injectable()
export class StatisticsService {
    private _calculation$ = new Subject<StatisticResult>();

    constructor(private themeService: ThemeService) {
        themeService.list.subscribe((themeList: ThemeList) => this.updateCalculation(themeList));
    }

    get calculation(): Observable<StatisticResult> {
        return this._calculation$.asObservable();
    }

    updateCalculation(newData: ThemeList | GroupList) {
        // ... do stuff
        this._calculation.next(statisticResult);
    }
}


/* statistics.component.ts */
@Component({
  selector: 'statistics',
  template: '<p>{{ statisticResult$ | async }}</p>'
})
export class StatisticsComponent {
    statisticResult$: Observable<StatisticResult>;

    constructor(private statisticsService: StatisticsService) {
        this.statisticResult$ = statisticsService.calculation;
    }
}