如何利用角度变化检测来提高性能?



我正在创建我的第一个开源项目,一个学校成绩簿。我是棱角刚开始的。 问题:如何提高成绩簿应用程序的运行时性能?表单控件是根据学生和作业动态生成的。渲染花费的时间比预期的要长。

我尝试分离更改检测器,但在触发更改检测时仍然花费太多时间。

当我研究 chrome 开发工具时,这是大部分时间花在进行更改检测上的地方。

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

}

斯塔克闪电战 https://stackblitz.com/github/omarolivo/Gradebook

Github:https://github.com/omarolivo/Gradebook

如何以更好的性能动态生成表单控件的行和列?

更新

在调查了导致整体性能主要问题的原因之后,更改检测在很大程度上会减慢组件的速度。我试图将数据数组转换为 RxJS 可观察的。我仍在努力进行更改检测。

关于有效使用更改检测的"正确"模式/架构的任何建议?

我很惊讶地认为ChangeDetection导致了这个问题,直到我意识到事实并非如此。您在那里看到的是误报。真正的瓶颈在于对<form>元素的繁重FormGroup的分配/呈现(当更改检测运行并更新值时,恰好发生这种情况)。

我建议使用 Angular 的 Resolve Guards 来"绕过"修改FormGroup时发生的所有更改检测,但这不会有太大区别(我对其进行了测试,然后意识到真正的问题在其他地方)。我实际上建议仍然这样做,不是出于性能原因,而是出于架构原因。我会将所有逻辑移动到服务,然后让守卫注入该服务并使用它来调用解析调用。

真正的问题在于表单包含的FormGroups数量。您正在查看 25 个人 x 39 列 =975FormGroups。这些FormGroups中的每一个都包含3个FormControls,总计近3000个。这是非常大的,我不认为有任何开箱即用的解决方案。

我建议做的是尝试在任何给定时间尽量减少可见字段的数量(因为无论如何没有人希望看到 975 个字段)。您可以将*ngFor元素拆分为更小的、分割的*ngFor元素,然后将其中一些元素包装在某些*ngIf逻辑中,这样它们就不会总是呈现(例如,当当前滚动位置靠近元素顶部时,*ngIf的计算结果可能为 true)。

您可以做的另一件事是研究更复杂的*ngFor元素延迟加载。我发现了一篇有趣的文章,作者引导您创建一个"懒惰"*ngFor指令。我不能保证它的质量(或可行性),但它绝对值得一试。

与往常一样,OnPush更改检测几乎是必须的,在这种情况下,这将对性能有所帮助。

如果我想到其他任何事情,我会回来编辑这篇文章。

祝你好运!

编辑:

Angular CDK内置了对虚拟滚动的支持。您可以使用<cdk-virtual-scroll-viewport>标记创建可滚动容器,然后将*ngFor指令替换为*cdkVirtualFor。API 的其余部分是相同的。

简要引用文档:

<cdk-virtual-scroll-viewport>通过仅呈现适合屏幕的项目来高性能地显示大型元素列表。在任何浏览器中加载数百个元素都可能很慢;虚拟滚动提供了一种高性能的方式来模拟正在呈现的所有项目,方法是使容器元素的高度与要呈现的元素总数的高度相同,然后仅呈现视图中的项目。

最新更新