我正在创建我的第一个开源项目,一个学校成绩簿。我很有棱角。问题:如何提高成绩簿应用程序的运行时性能?表单控件是根据学生和作业动态生成的。渲染花费的时间超过了预期。
我试图拆开变化探测器,但在触发变化探测时仍然花费太多时间。
当我研究chrome dev工具时,这是大部分时间用于进行变更检测的地方。
private createFormControls( ) {
const gradeGroup = this.gradeControls;
this.clearAllGradeControls(gradeGroup);
for (let i = 0; i < this.gradebook.students.length; i++) {
const student = this.gradebook.students[i];
const studentGrades = this.gradebook.grades.filter( g => g.userId == student.userId);
for (let j = 0; j < this.gradebook.assignments.length; j++) {
const assignment = this.gradebook.assignments[j];
const key = this.createKey(student.userId, assignment.id);
const grade = studentGrades.find( g => g.assignmentId == assignment.id );
let fg = new FormGroup({
grade: new FormControl(grade ? grade.grade : ''),
userId: new FormControl(student.userId),
assignmentId: new FormControl(assignment.id),
});
gradeGroup.addControl(key, fg);
}
}
}
Stackblitz https://stackblitz.com/github/omarolivo/Gradebook
Github:https://github.com/omarolivo/Gradebook
如何以更好的性能动态生成表单控件的行和列?
UPDATE
在研究导致整体性能出现主要问题的最新情况后,更改检测大部分会降低组件的速度。我试图将数据数组转换为RxJS可观察数据。我仍然在努力改变检测。
有关“正确”模式/架构的任何建议,以有效地使用变更检测?
我很惊讶地认为ChangeDetection导致了这个问题,直到我意识到它不是。你所看到的是误报。真正的瓶颈在于将重FormGroup
赋值给<form>
元素(当更改检测运行且值更新时恰好发生这种情况)。
我打算建议使用Angular的Resolve Guards来“绕过”修改FormGroup
时发生的所有变化检测,但这并没有太大的区别(我测试了它然后意识到真正的问题在其他地方)。我实际上建议仍然这样做,不是出于性能原因,而是出于架构原因。我将所有逻辑移动到服务,然后让守卫注入该服务并使用它来调用解析调用。
真正的问题在于您的表单包含的FormGroups
数量。你在39列= 975 FormGroups
看25人。然后每个FormGroups
包含3个FormControls
,总计近3千。这是非常大的,我不相信有任何开箱即用的解决方案。
我建议做的是尝试在任何给定时间最小化可见字段的数量(因为没有人想要预先看到975个字段)。您可以将*ngFor
元素拆分为较小的,分开的*ngFor
元素,然后将它们中的一些包裹在某些*ngIf
逻辑中,这样它们就不会被渲染(当当前滚动位置靠近元素顶部时,*ngIf
可能会评估为true例如)。
你可以做的另一件事是研究*ngFor
元素的更复杂的延迟加载。我发现了一个有趣的article,作者通过创建一个'懒惰的'*ngFor
指令来指导你。我不能保证这个的质量(或可行性),但绝对值得一试。
与往常一样,OnPush
变化检测几乎是必须的,在这种情况下将有助于性能。
如果我想到别的什么,我会回来编辑这篇文章。
祝好运!
编辑:
Angular CDK支持内置的Virtual Scrolling。您可以使用<cdk-virtual-scroll-viewport>
标记创建可滚动容器,然后使用*ngFor
替换*cdkVirtualFor
指令。 API的其余部分是相同的。
简要引用文档:
<cdk-virtual-scroll-viewport>
仅通过渲染适合屏幕的项目来显示大量元素列表。在任何浏览器中加载数百个元素都会很慢;虚拟滚动允许通过使容器元素的高度与要渲染的元素总数的高度相同,然后仅渲染视图中的项目,以高效方式模拟正在渲染的所有项目。