垃圾 collection 在使用 ng-repeat AngularJS 构建大型 table 后在 Internet Explorer 中需要很长时间
Garbage collection takes a very long time in Internet Explorer after building a large table with ng-repeat AngularJS
我正在使用 AngularJS (1.2.26) 中的 ng-repeat 指令构建大型 table(3,000 多行)。数据是一个非常简单的时间和温度数组数组[[time, temperature], [time, temperature], ...]
。
这是数据在 table 中的显示方式(使用 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 库来减少 angular 观察者的数量。这是一份报告,因此我们不需要维护数据绑定。
加载数据和呈现报告在 Chrome 或 Firefox 上大约需要 4 秒,在 Internet Explorer (11) 上大约需要 8 秒。但是,在 Internet Explorer 上构建 table 后,浏览器最多需要两分钟来执行垃圾处理 Collection(根据 UI 响应选项卡)。
我需要更多 "reputation" 到 post 图片,所以我会尽我所能描述发生的事情。
整个 table 渲染过程是 xhr.onreadystatechange
事件侦听器的结果(此后已从 1.3 中的 angular 中删除)。每行和跨度都添加到 table 中,使用来自 jQuery 的 appendChild()
-> insertBefore()
函数或来自浏览器的 innerHTML
函数。这些发生了数千次,占了我之前提到的 ~8 秒。这些完成后,紧随其后的是几行垃圾 collection,总共需要 60 多秒。
在没有输出图片的情况下,这是在最后一个 appendChild()
之后开始执行的时间列表,后跟总执行时间(window).
- 0.24 秒,0.0065 毫秒
- 0.36 秒,13.83 毫秒
- 0.85 秒,0.31 毫秒
- 10 秒,0.0042 毫秒
- 57 秒,25.54 毫秒
- 60 秒,0.048 毫秒
然后,在剩下的过程继续之前,还有大约 10 秒的间隔。
我不明白这是怎么回事,因为每个垃圾collection很短,但他们之间的差距却很长。我不太了解浏览器中的垃圾collection,所以我妨碍了我的理解。 Chrome 或 Firefox 中不会发生这种情况。
我遵循了有关分析内存分析的各种指南。我不相信有内存泄漏。同样,由于我的声誉,我无法添加更多链接,但我遵循了标题为 "JavaScript Memory Profiling" 的 Chrome 和标题为 "Improving UI Responsiveness".
的 IE。
我不确定其中的另一部分是否相关,但我会在这里提及以防万一。当您在此延迟期间 运行 分析 session 时,IE 表示延迟发生在 AngularJS $$RAFProvider
的 requestAnimationFrame https://github.com/angular/angular.js/blob/master/src/ng/raf.js#L15
函数期间。这可能与 AngularJS 通过 ng-repeat 添加的每一行都会触发一个 "enter" 事件有关。到目前为止,我一直在尝试禁用该动画事件,但没有成功。
非常感谢任何建议或疑难解答提示。具体来说,如果我可以在垃圾 collection 上添加一个断点以查看发生了什么,那就太好了,但我认为我不能那样做。
对于 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>
为绑定一次添加'::'。
如果您不添加一次绑定,当您滚动 table 时,同一项目的格式函数将被调用多次。所以对于格式,你应该使用像这样的日期过滤器:
<span>{{item.time | date: 'yyyy/MM/DD'}}</span>
经过大量调查,我认为我弄清楚了问题所在,或者至少是一个潜在的问题。
我正在渲染的 table 有两列 - 时间和温度。时间列有两个 <span>
元素。因此,对于每一行,Angular 都在为 "enter" 动画标记元素,就像它为 ng-repeat
的每个元素所做的那样。作为 Angular 动画过程的一部分,Angular 通过 $RAFProvider 从浏览器请求动画帧。当我在 Internet Explorer 中分析该过程并查看调用堆栈时,这就是巨大的延迟所在。我最初认为这不是问题所在,但经过大量故障排除后,我开始认为 Internet Explorer requestAnimationFrame 方法无法像 Chrome 或 Firefox 一样快速地处理 ~9000 次调用。
为了解决这个问题,我选择实施 ngInfiniteScroll 并且效果很好。如果用户真的想要完整的报告,我们将通过不同的代码路径生成完整的 3,000 行报告。
我正在使用 AngularJS (1.2.26) 中的 ng-repeat 指令构建大型 table(3,000 多行)。数据是一个非常简单的时间和温度数组数组[[time, temperature], [time, temperature], ...]
。
这是数据在 table 中的显示方式(使用 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 库来减少 angular 观察者的数量。这是一份报告,因此我们不需要维护数据绑定。
加载数据和呈现报告在 Chrome 或 Firefox 上大约需要 4 秒,在 Internet Explorer (11) 上大约需要 8 秒。但是,在 Internet Explorer 上构建 table 后,浏览器最多需要两分钟来执行垃圾处理 Collection(根据 UI 响应选项卡)。
我需要更多 "reputation" 到 post 图片,所以我会尽我所能描述发生的事情。
整个 table 渲染过程是 xhr.onreadystatechange
事件侦听器的结果(此后已从 1.3 中的 angular 中删除)。每行和跨度都添加到 table 中,使用来自 jQuery 的 appendChild()
-> insertBefore()
函数或来自浏览器的 innerHTML
函数。这些发生了数千次,占了我之前提到的 ~8 秒。这些完成后,紧随其后的是几行垃圾 collection,总共需要 60 多秒。
在没有输出图片的情况下,这是在最后一个 appendChild()
之后开始执行的时间列表,后跟总执行时间(window).
- 0.24 秒,0.0065 毫秒
- 0.36 秒,13.83 毫秒
- 0.85 秒,0.31 毫秒
- 10 秒,0.0042 毫秒
- 57 秒,25.54 毫秒
- 60 秒,0.048 毫秒
然后,在剩下的过程继续之前,还有大约 10 秒的间隔。
我不明白这是怎么回事,因为每个垃圾collection很短,但他们之间的差距却很长。我不太了解浏览器中的垃圾collection,所以我妨碍了我的理解。 Chrome 或 Firefox 中不会发生这种情况。
我遵循了有关分析内存分析的各种指南。我不相信有内存泄漏。同样,由于我的声誉,我无法添加更多链接,但我遵循了标题为 "JavaScript Memory Profiling" 的 Chrome 和标题为 "Improving UI Responsiveness".
的 IE。我不确定其中的另一部分是否相关,但我会在这里提及以防万一。当您在此延迟期间 运行 分析 session 时,IE 表示延迟发生在 AngularJS $$RAFProvider
的 requestAnimationFrame https://github.com/angular/angular.js/blob/master/src/ng/raf.js#L15
函数期间。这可能与 AngularJS 通过 ng-repeat 添加的每一行都会触发一个 "enter" 事件有关。到目前为止,我一直在尝试禁用该动画事件,但没有成功。
非常感谢任何建议或疑难解答提示。具体来说,如果我可以在垃圾 collection 上添加一个断点以查看发生了什么,那就太好了,但我认为我不能那样做。
对于 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>
为绑定一次添加'::'。
如果您不添加一次绑定,当您滚动 table 时,同一项目的格式函数将被调用多次。所以对于格式,你应该使用像这样的日期过滤器:
<span>{{item.time | date: 'yyyy/MM/DD'}}</span>
经过大量调查,我认为我弄清楚了问题所在,或者至少是一个潜在的问题。
我正在渲染的 table 有两列 - 时间和温度。时间列有两个 <span>
元素。因此,对于每一行,Angular 都在为 "enter" 动画标记元素,就像它为 ng-repeat
的每个元素所做的那样。作为 Angular 动画过程的一部分,Angular 通过 $RAFProvider 从浏览器请求动画帧。当我在 Internet Explorer 中分析该过程并查看调用堆栈时,这就是巨大的延迟所在。我最初认为这不是问题所在,但经过大量故障排除后,我开始认为 Internet Explorer requestAnimationFrame 方法无法像 Chrome 或 Firefox 一样快速地处理 ~9000 次调用。
为了解决这个问题,我选择实施 ngInfiniteScroll 并且效果很好。如果用户真的想要完整的报告,我们将通过不同的代码路径生成完整的 3,000 行报告。