Angular2 NGRX 调度时的性能问题?

Angular2 NGRX Performance Issues On Dispatch?

我一直在 Angular2/CLI/NGRX 开发一个应用程序,直到最近一切都很顺利。我注意到性能出现了一些相当大的峰值,尤其是在同一容器内进行连续调度时。

例如,假设我定义了以下内容:

public appEnvironment$: Observable<IEnvironment>;

public assessment$: Observable<IAssessment>;
public assessmentComments$: Observable<ICommentActivity[]>;
public assessmentEvidence$: Observable<IEvidenceActivity[]>;
public assessmentIssues$: Observable<IIssueActivity[]>;
public assessmentSurvey$: Observable<ISurvey>;
public assessmentUsers$: Observable<ISystemUser[]>;
public assessmentSelectedNode$: Observable<ISurveyChildNode>;

constructor(private _store: Store<fromDomain.State>, private _route: ActivatedRoute) {
  this.appEnvironment$ = _store.select(fromDomain.getEnvironment).share();

  this.assessment$ = _store.select(fromDomain.getAssessment).share();
  this.assessmentComments$ = _store.select(fromDomain.getAssessmentComments).share();
  this.assessmentIssues$ = _store.select(fromDomain.getAssessmentIssues).share();
  this.assessmentEvidence$ = _store.select(fromDomain.getAssessmentEvidence).share();
  this.assessmentSurvey$ = _store.select(fromDomain.getAssessmentSurvey).share();
  this.assessmentUsers$ = _store.select(fromDomain.getAssessmentUsers).share();
  this.assessmentSelectedNode$ = _store.select(fromDomain.getAssessmentSelectedNode).share();

  this.openAssessmentId = _route.snapshot.params['id'];

  this._store.dispatch(new LoadAssessmentAction(this.openAssessmentId));
}

还值得注意的是,以上是加载子组件所需的所有状态选择及其跨多个组件共享的数据(因此 .share()),例如:

<opt-drawer-index
  #drawerShow
  [leftHeading]="'Survey Info'"
  [leftIcon]="'fa-bars'"
  [rightHeading]="'Assessment Details'"
  [onForceChange]="assessmentSelectedNode$ | async">
  <section drawer-left-content>
    <opt-assessment-show-survey-info
      [appEnvironment]="appEnvironment$ | async"
      [assessment]="assessment$ | async"
      [assessmentUsers]="assessmentUsers$ | async"></opt-assessment-show-survey-info>
  </section>
  <section drawer-content>
    <opt-assessment-show-content
      [appEnvironment]="appEnvironment$ | async"
      [assessment]="assessment$ | async"
      [assessmentSurvey]="assessmentSurvey$ | async"
      (selectedNode)="changeSelectedNode($event)"></opt-assessment-show-content>
  </section>
  <section drawer-right-content>
    <opt-assessment-show-details
      [activeNode]="assessmentSelectedNode$ | async"
      [appEnvironment]="appEnvironment$ | async"
      [assessment]="assessment$ | async"
      [assessmentComments]="assessmentComments$ | async"
      [assessmentEvidence]="assessmentEvidence$ | async"
      [assessmentIssues]="assessmentIssues$ | async"
      [assessmentUsers]="assessmentUsers$ | async"></opt-assessment-show-details>
  </section>
</opt-drawer-index>

初始负载很好,运行良好。我的冻结状态处于活动状态,并且该状态内没有发生任何突变。所有组件也都在使用 OnPush 策略。

问题出在中心内容组件中我有一个与容器组件通信的事件发射器。它向 'select' 发送一个对象,并通过调度程序触发一个操作,以使用所选选项更新状态。第一对点击 运行 很棒,然后您开始注意到一些严重的功耗,因为您继续点击子组件的不同区域。就好像调度员似乎陷入了困境。

我尝试了一些方法,例如使用 combineLatest() 和其他工具来减轻更新的负担,但这似乎让事情变得更糟。目前应用加载数据的方式如下:

Load Assessment -> After Load Assessment Effect -> Select Assessment -> After Load Selected Assessment Effect

还有其他人 运行 遇到性能问题吗?它与 NGRX 和我的设置方式无关吗?我主要使用 NGRX 示例应用程序作为如何布置我的设置的参考点。

编辑

这是我遇到的问题的时间表。好像点击事件的时间呈指数级增长?

编辑 2

我正在使用重新选择,这是在后续点击后挂起的页面的效果:

import {Injectable} from "@angular/core";

// NGRX
import {Actions, Effect} from "@ngrx/effects";
import {Action} from "@ngrx/store";

// Services
import {AssessmentService} from "./assessment.service";
import {SurveyService} from "../survey/survey.service";
import {SystemUserService} from "../system-user/system-user.service";

// Observable and operators
import {Observable} from "rxjs/Observable";
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/concatMap';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/map';

// Misc
import * as assessment from './assessment.actions';
import * as assessmentNav from './navigation/assessments-navigation.actions';

@Injectable()
export class AssessmentEffects {
  constructor(private actions$: Actions, private assessmentsService: AssessmentService,
              private surveyService: SurveyService, private systemUserService: SystemUserService) { }

  @Effect()
  effLoadAssessment$: Observable<Action> = this.actions$
    .ofType(assessment.ActionTypes.LOAD_ASSESSMENT)
    .map((action: assessment.LoadAssessmentAction) => action.payload)
    .switchMap(guid => {
      return this.assessmentsService.getAssessment(guid)
        .map(v => new assessment.LoadAssessmentCompleteAction(v));
    });

  @Effect()
  effAfterLoadAssessment: Observable<Action> = this.actions$
    .ofType(assessment.ActionTypes.LOAD_ASSESSMENT_COMPLETE)
    .map((action: assessment.LoadAssessmentCompleteAction) => action.payload)
    .mergeMap(theAssessment => {
      return [
        new assessment.LoadAssessmentSurveyAction(theAssessment.surveyID),
        new assessmentNav.AssessmentNavAddAction(theAssessment),
        new assessment.LoadAssessmentUserAction(theAssessment.instanceOwner_SystemUserID)
      ];
    });

  @Effect()
  effLoadAssessmentComments$: Observable<Action> = this.actions$
    .ofType(assessment.ActionTypes.LOAD_ASSESSMENT_COMMENTS)
    .map((action: assessment.LoadAssessmentCommentsAction) => action.payload)
    .switchMap(multiRequest => {
      return this.assessmentsService
        .getAssessmentComments(multiRequest.assessmentId, multiRequest.type, multiRequest.nodeId)
        .map(v => new assessment.LoadAssessmentCommentsCompleteAction(v));
    });

  @Effect()
  effAfterSelectedNode$: Observable<Action> = this.actions$
    .ofType(assessment.ActionTypes.SELECT_ASSESSMENT_NODE)
    .map((action: assessment.SelectedNodeAction) => action.payload)
    .mergeMap(theNode => {
      return [
        new assessment.LoadAssessmentCommentsAction({
          type: 'Comments',
          nodeId: theNode.id,
          assessmentId: theNode.assessmentId
        }),
        new assessment.LoadAssessmentIssuesAction({
          type: 'Issues',
          nodeId: theNode.id,
          assessmentId: theNode.assessmentId
        }),
        new assessment.LoadAssessmentEvidenceAction({
          type: 'Attachments',
          nodeId: theNode.id,
          assessmentId: theNode.assessmentId
        })
      ];
    });

  @Effect()
  effLoadAssessmentIssues$: Observable<Action> = this.actions$
    .ofType(assessment.ActionTypes.LOAD_ASSESSMENT_ISSUES)
    .map((action: assessment.LoadAssessmentIssuesAction) => action.payload)
    .switchMap(multiRequest => {
      return this.assessmentsService
        .getAssessmentIssues(multiRequest.assessmentId, multiRequest.type, multiRequest.nodeId)
        .map(v => new assessment.LoadAssessmentIssuesCompleteAction(v));
    });

  @Effect()
  effLoadAssessmentEvidence$: Observable<Action> = this.actions$
    .ofType(assessment.ActionTypes.LOAD_ASSESSMENT_EVIDENCE)
    .map((action: assessment.LoadAssessmentEvidenceAction) => action.payload)
    .switchMap(multiRequest => {
      return this.assessmentsService
        .getAssessmentEvidence(multiRequest.assessmentId, multiRequest.type, multiRequest.nodeId)
        .map(v => new assessment.LoadAssessmentEvidenceCompleteAction(v));
    });

  @Effect()
  effLoadAssessmentUser$: Observable<Action> = this.actions$
    .ofType(assessment.ActionTypes.LOAD_ASSESSMENT_USER)
    .map((action: assessment.LoadAssessmentUserAction) => action.payload)
    .concatMap(guid => {
      return this.systemUserService.getSystemUser(guid)
        .map(v => new assessment.LoadAssessmentUserCompleteAction(v));
    });

  @Effect()
  effLoadAssessmentSurvey$: Observable<Action> = this.actions$
    .ofType(assessment.ActionTypes.LOAD_ASSESSMENT_SURVEY)
    .map((action: assessment.LoadAssessmentSurveyAction) => action.payload)
    .switchMap(guid => {
      return this.surveyService.getSurvey(guid)
        .map(v => new assessment.LoadAssessmentSurveyCompleteAction(v));
    });
}

减速实际上与 @ngrx/store-devtools 有关。在我从应用程序中删除模块后,速度非常惊人。我们希望使用该工具来快照和重放状态,但我不确定我们是否可以在性能下降的情况下继续沿着这条路走下去。