简体   繁体   English

Angular2中长列表渲染的性能不佳

[英]Poor performance of long list rendering in Angular2

I have an application with a history stream, containing user actions. 我有一个包含用户操作的历史流应用程序。 The history is displayed by days or whole weeks. 历史记录按天或整周显示。 During one day there is approximately around 400-2k of events to display. 在一天内,大约有大约400-2k的活动要展出。

There are few types of actions that may occur and each one is displayed differently (eg comment or object modification). 可能发生的动作类型很少,并且每个动作的显示方式不同(例如注释或对象修改)。 Therefore there is some logic in each loop iteration to determinate the final structure of each element. 因此,在每个循环迭代中存在一些逻辑以确定每个元素的最终结构。

The problem is that it lots of time to render, ~1300 elements renders around 6s. 问题是它有很多时间渲染,~1300个元素渲染大约6s。 For me it is pretty long time to wait for such thing. 对我来说,等待这样的事情已经很久了。 I have tried to optimise the code to do the required minimum, but still the best I could get is 6s for ~1300 elements. 我已经尝试优化代码以达到所需的最小值,但是我能得到的最好的是〜1300个元素的6s。

The other bigger problem with that is freezed browser during the rendering which is not acceptable for such long time. 另一个更大的问题是在渲染过程中冻结浏览器,这是很长时间不可接受的。

I'm not sure if I have done something wrong or I have found a week spot of Angular2 which is not possible to resolve. 我不确定我做错了什么,或者我找到了Angular2的周点,这是无法解决的。 So any hint is welcome. 所以任何提示都是受欢迎的。 I'm not interested in advices like: use pagination or use infinite scroll, I'm am looking for a way to make it work faster and smother. 我对以下建议不感兴趣:使用分页或使用无限滚动,我正在寻找一种方法让它更快更好地工作。

I will also add that previously the history was rendered on the servers side and putting the result into the DOM was super quick, no matter of the number of events. 我还要补充说,以前历史记录是在服务器端呈现的,无论事件的数量如何,将结果放入DOM都非常快。 Further screenshots also shows that the real rendering time is just a very small part of the process. 进一步的屏幕截图还显示,实际渲染时间只是整个过程的一小部分。

I have prepared simplified version of the rendering code in the plunker which shows the problem: http://plnkr.co/edit/QrYmYezmlV3MkQV5bOA8?p=preview 我在plunker中准备了渲染代码的简化版本,显示了问题: http ://plnkr.co/edit/QrYmYezmlV3MkQV5bOA8?p = preview

The main rendering parts: 主要渲染部分:

Root ngFor element Root ngFor元素

<div class="history-stream">
  <div *ngFor="let action of history"
       class="activity" [ngClass]="{'first-of-user': action.firstOfUser, 'last-of-user': action.lastOfUser}">
    <p class="date" *ngIf="action.firstOfDay">{{ action.date | date:'mediumDate' }}</p>
    <div class="user-entry" [ngSwitch]="action.type">
      <comment *ngSwitchCase="'comment'" [object]="action"></comment>
      <modified *ngSwitchCase="'modified'" [object]="action"></modified>
    </div>
  </div>
</div>

Comment component: 评论组件:

<div class="entry comment" [ngClass]="{'comment-resolved': object.extra.is_resolved}">
  <a href="{{ getDeleteUrl(object.extra.comment_id) }}" data-target="metabase-modal-ajax" class="comment-action">Delete</a>
  <a href="#" class="comment-action" *ngIf="!object.extra.is_resolved" (click)="resolveComment($event)">Mark as resolved</a>
  <a href="#" class="comment-action" *ngIf="object.extra.is_resolved" (click)="unResolveComment($event)">Unresolve</a>
  <p class="action" [innerHTML]="object.action"></p>
  <p>{{ object.comment }}</p>
  <small class="text-muted">{{ object.date | date:'shortTime' }} <span class="dot">&middot;</span> {{ object.date | date:'shortTime' }}</small>
</div>

Modified event component: 修改事件组件:

<div class="entry modified">
  <p class="action" [innerHTML]="object.action"></p>
  <ul class="changes list-unstyled">
    <li *ngFor="let change of object.changes">
      <span class="attribute">{{ change.attribute }}:</span>&nbsp;
      <modified-value [change]="change.from"></modified-value>
      <span class="arrow">&rarr;</span>&nbsp;
      <modified-value [change]="change.to"></modified-value>
      <small class="time text-muted">{{ change.date | date:'shortTime' }} <span class="dot">&middot;</span> {{ change.date | date:'shortTime' }}</small>
    </li>
  </ul>
</div>

And modified-value component: 和修改值组件:

<span [ngSwitch]="getChangeType()">
  <span *ngSwitchCase="'complex'">
    <span *ngFor="let item of change">
      <span class="badge">{{ item.tag }}</span>
      <span [ngSwitch]="isArray(item.value)">
        <span *ngSwitchCase="true">
          <span *ngFor="let valueItem of item.value" class="value tag">{{ valueItem }}</span>
          <span *ngIf="isEmpty(item.value)" class="value text-muted">None</span>
        </span>
        <span *ngSwitchCase="false">
          <span *ngIf="item.value" class="value">{{ item.value }}</span>
          <span *ngIf="!item.value" class="value text-muted">None</span>
        </span>
      </span>
    </span>
  </span>
  <span *ngSwitchDefault>
    <span *ngIf="change" class="value">{{ change }}</span>
    <span *ngIf="!change" class="value text-muted">None</span>
  </span>
</span>

Also a few screenshots of profiles recording: 还有一些配置文件的截图:

在此输入图像描述

在此输入图像描述

Angular 7 introduced virtual scroll feature. Angular 7引入了虚拟滚动功能。 It can help dramatically increase render performance - only visible part of list is added to DOM. 它可以帮助显着提高渲染性能 - 只有可见的部分列表被添加到DOM中。 But it also add some restrictions, like fixed row size 但它也增加了一些限制,比如固定行大小

There are a few good ways to improve performance in Angular. 有一些提高Angular性能的好方法。 I would suggest you read this: http://blog.mgechev.com/2015/03/02/immutability-in-angularjs-immutablejs/ on using immutable data structures to improve performance. 我建议你阅读: http//blog.mgechev.com/2015/03/02/immutability-in-angularjs-immutablejs/关于使用不可变数据结构来提高性能。

Let me know if you have any questions after reading. 如果您在阅读后有任何疑问,请告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM