Angular2 NGRX Performance Issues On Dispatch?

岁酱吖の 提交于 2019-12-08 03:16:40

问题


I've been working on an application in Angular2/CLI/NGRX and things have been going well until recently. I'm noticing some pretty big spikes in performance especially with consecutive dispatches within the same container.

For example lets say I have the following defined:

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));
}

It's also worth noting that the above is all the state selection required to load the child components and their data shared across multiple components (hence the .share()) something like:

<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>

The initial load is great and works well. I have the freeze-state active and no mutations are occurring within the state. All components are utilizing the OnPush strategy as well.

The problem is within the center content component I have an event emitter that talks with the container component. It sends up an object to 'select' and that fires off an action through the dispatcher to update the state with the selected option. The first couple clicks run great and then you start to notice some serious power consumption as you continue to click on different areas throughout the child components. It's almost as if the dispatcher seems to be bogged down.

I've tried a few things like using combineLatest() and other tools to lessen the burden on the updates, however that seemed to make matters worse. Currently the way the application loads data is as follows:

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

Anyone else run into performance issues? Is it something unrelated to NGRX and the way that I have things setup? I've mainly used the NGRX example app as a reference point for how to lay out my setup.

Edit

Here's a timeline representation of the problem I'm having. It's almost as though the click event is getting exponentially longer?

Edit 2

I am using reselect and here's the effects for the page that is hanging after subsequent clicks:

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));
    });
}

回答1:


The slowdown was actually related to the @ngrx/store-devtools. After I removed the module from the application the speed was phenomenal. We were hoping to use the tooling for snapshotting and replaying state, but I'm not sure we can go down that route anymore with the performance hit.



来源:https://stackoverflow.com/questions/42354606/angular2-ngrx-performance-issues-on-dispatch

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!