【问题标题】:Angular2 NGRX Performance Issues On Dispatch?Angular2 NGRX 调度时的性能问题?
【发布时间】:2017-07-10 07:48:18
【问题描述】:

我一直在 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 策略。

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

我尝试了一些方法,例如使用 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));
    });
}

【问题讨论】:

  • 您是否使用reselect 来创建您的选择器?
  • 你能分享你的效果吗?
  • @cgatian 是的,我正在使用reselect 为状态片段创建选择器。 @Maxime 我已经附加了导致速度变慢的页面效果。我想知道该州的这一特定部分是否变得太大。我们确实从服务中获得了大量我们没有使用的数据,我正在使用Object.assign 来重置更改的状态部分。将状态进一步分割成更小的部分可能是有益的。

标签: angular rxjs rxjs5 ngrx ngrx-effects


【解决方案1】:

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

【讨论】:

  • 好吧,store-devtools 应该在生产环境中禁用。
  • 我见过一些其他公司在 React 世界中启用它们的故事。利用他们的 API 提供的一些工具。我认为现在的主要问题是我们的遗留服务喜欢在我们只需要一小部分的时候返回世界。
  • 哇!我不敢相信现在有多快!我开始认为我在使用 ngrx 时犯了一个巨大的错误。多么宽慰
猜你喜欢
  • 2020-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-02
  • 1970-01-01
  • 2012-07-23
  • 2017-02-05
  • 1970-01-01
相关资源
最近更新 更多