2017-02-20 9 views
2

私はAngular2/CLI/NGRXのアプリケーションで作業してきましたが、最近までうまくいっています。私は、同じコンテナ内での連続したディスパッチで、特にパフォーマンスのかなり大きなスパイクに気付いています。Angular2 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のサンプルアプリケーションを、セットアップのレイアウト方法のリファレンスポイントとして使用しました。

編集

ここに私がいる問題のタイムライン表現です。 Clickイベントが指数関数的に長くなっているようです。

Timeline

編集私は再度選択使用して、ここで、後続のクリックした後ハングしているページのエフェクトです午前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)); 
 
    }); 
 
}

+0

セレクタを作成するのに 'reselect'を使用していますか? – cgatian

+0

あなたのエフェクトを共有できますか? – Maxime

+0

@cgatianはい私は 'reselect'を使って状態のセレクタを作成しています。 @Maxime私は減速の原因となったページのエフェクトを添付しました。この州の特定のスライスが大きすぎるのかどうか疑問に思います。我々は、サービスから戻って利用しない大量のデータを取得し、 'Object.assign'を実行して、変化する状態の部分をリセットしています。状態をさらに細かくスライスすることは有益でしょう。 – Aric

答えて

6

減速を実際に関連していた@ngrx/store-devtoolsにアプリケーションからモジュールを削除した後、スピードは驚異的でした。私たちは、スナップショットと状態の再現のためにツールを使用することを望んでいましたが、私はパフォーマンスヒットでもうそのルートを辿ることができないとは思っていません。

+0

まあ、store-devtoolsは本番環境では無効にする必要があります。 – maxisam

+0

私は、他の企業がReactの世界でそれらを有効にしているといういくつかの話を見てきました。 APIを使用して利用可能なツールの一部を活用します。私は今、主な問題は、小さなスライスだけが必要な時に世界を返すことを望むレガシーサービスだと思います。 – Aric

+0

うわー!今はどれくらい速いのか信じられない!私はngrxを使って大きなミスを犯したと思っていました。どのような安堵* phew * – Kesarion

関連する問題