我正在使用AngularJS(1.2.26)的ng-repeat指令构建一个大表(3,000多行)。数据是一个非常简单的时间和温度数组[[time, temperature], [time, temperature], ...]
。
这是数据在表格中的显示方式(使用Slim templating):
table.table.table-bordered
thead
tr
th.time.first-child= t('Time')
th.temperature.sensor
tbody
tr[bindonce ng-repeat="item in readings"]
td.datetime
span.date bo-text="formatDate(item.time)"
span.time bo-html="formatTime(item.time)"
td bo-text="item.reading.temperature | number: 2"
如您所见,我们正在使用bind once库来减少角度观察者的数量。这是一份报告,因此我们不需要维护数据绑定。
在Chrome或Firefox上加载数据并呈现报告大约需要4秒钟,在Internet Explorer(11)上大约需要8秒钟。但是,在Internet Explorer上构建表后,浏览器最多需要两分钟才能执行垃圾收集(根据UI响应性选项卡)。
我需要更多"声誉"发布图片,所以我会尽力描述正在发生的事情。
整个表格渲染过程是xhr.onreadystatechange
事件监听器(后来从1.3中的角度移除)的结果。使用appendChild()
- >将每行和每个范围添加到表格中来自jQuery的insertBefore()
函数或来自浏览器的innerHTML
函数。这些发生了数千次,占我之前提到的~8秒。完成这些操作后,会立即进行几行垃圾收集,总共需要60秒以上。
如果没有输出图片,这是在最后appendChild()
之后开始执行的时间列表,后面是总执行时间(窗口中条形图的长度)。
然后,在剩余的过程进行之前还有大约10秒的另一个间隙。
我不明白这里发生了什么,因为每个垃圾收集都很短,但它们之间的差距很大。我对浏览器中的垃圾收集知之甚少,所以我的理解会受到阻碍。这不是在Chrome或Firefox中发生的。
我已经关注了有关分析内存分析的各种指南。我不相信有内存泄漏。同样,由于我的声誉,我无法添加更多链接,但我跟着Chrome一个名为" JavaScript Memory Profiling"和IE标题为“#34;提高用户界面响应能力"。
还有另一部分,我不确定它是否相关,但我会在这里提及它,以防万一。在此延迟期间运行性能分析会话时,IE表示延迟是在AngularJS https://github.com/angular/angular.js/blob/master/src/ng/raf.js#L15
的requestAnimationFrame $$RAFProvider
函数期间。这可能与AngularJS触发"输入"通过ng-repeat添加的每一行的事件。到目前为止,我一直在尝试禁用该动画事件。
非常感谢任何建议或疑难解答提示。具体来说,如果我可以在垃圾收集上添加一个断点来查看发生了什么,那就太棒了,但我不认为我能做到这一点。
答案 0 :(得分:3)
经过多次调查,我认为我弄清楚问题是什么,或者至少是一个潜在的问题。
我正在渲染的表有两列 - 时间和温度。时间列有两个<span>
个元素。因此,对于每一行,Angular都标记了&#34;输入&#34;动画,因为它为ng-repeat
的每个元素。作为Angular动画过程的一部分,Angular通过$RAFProvider从浏览器请求动画帧。当我在Internet Explorer中分析该进程并查看调用堆栈时,这是一个巨大的延迟。我原本以为这不是问题所在,但经过大量的故障排除后,我开始认为Internet Explorer requestAnimationFrame方法几乎不能像Chrome或Firefox一样快速处理~9000个调用。
为了解决这个问题,我选择实施ngInfiniteScroll并且它运作良好。如果用户真的想要完整报告,我们将通过不同的代码路径生成完整的3,000行报告。
答案 1 :(得分:0)
对于ng-repeat,angular将为重复进行双向绑定的每个项目创建一个范围。但是在您的代码中,没有必要,您只需显示数据。
如果您使用的是angularjs 1.3.x以上,则可以使用binging-once功能,然后不会创建这些范围。
我不熟悉那个模板。但你在TR中使用'bindonce',如果在angularjs中是'bindonce',我认为你应该使用1.3.x版本。
另一个问题是:
span.date bo-text="formatDate(item.time)"
您使用数据格式的函数。如上所述,你应该使用'bind-once'。如果你使用js,那就是:
<span>{{::formatDate(item.time)}}</span>
为绑定添加'::'一次。
如果不添加bind一次,当您滚动表格时,同一项目的格式化功能将被多次调用。因此,对于格式,您应该使用日期过滤器,如:
<span>{{item.time | date: 'yyyy/MM/DD'}}</span>