我一直在 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));
});
}