在迭代 array 非常大的情况下,重复性能降低

分享于 

9分钟阅读

Web开发

  繁體 雙語

问题

你可能在使用 ng-repeat 指令iterate非常大的array 迭代时可能遇到问题,例如你可能需要显示几个属性,如 change,显示或者隐藏某些html标签,具体取决于某些条件。 在这种情况下,你可以面临性能降级问题,因为wince创建了大量与 array.length 成比例的数字。

解决方案

首先,我们可以说,如果你有超过 2k 个记录,你可以能不会在屏幕上显示它们。 let last的情况下,我们可以告诉AngularJS只显示所有记录的,这样,我们就可以 rows rows行,这意味着观察者的数量也会受到限制,它可以解决我们的性能问题。

幸运的是,AngularJS提供的功能为 limitTo: 在当前时刻,我们可以指定 array的哪一部分,以帮助你指定的部分:

<code>{{ limitTo_expression | limitTo : limit : begin}}</code>

其中,部分 limit 部分和 begin size部分的索引将从其中开始。 那么我们应该做的就是根据滚动位置改变 begin 参数。 对于这里任务,我们将创建 smartScroll 指令:

.directive("smartScroll", function() {
 return {
 restrict: 'E',
 scope: {
 to: '=',
 length: '@' },
 template: `
 <div style="overflow:auto;width:15px">
 <div></div></div> `,
 link: function(scope, element, attrs) {
 //set height of root divvar root = angular.element(element.find('div')[0]);
 root.css('height', attrs.height);
 scope.$watch('length', function() {
 //when array.length is changed we will change height of inner div //to correct scrolling presentation of parent div accordinglyvar height = (scope.length - attrs.limit) * attrs.sens + attrs.height * 1;
 angular.element(element.find('div')[1]).css('height', height);
 //if we won't need scrolling anymore, we can hide it //and shift scrolling to initial top positionif (scope.length <= attrs.limit) {
 root[0].scrollTop = 0;
 root.css('display', 'none');
 scope.to = 0;
 } else root.css('display', 'block');
 });
 //when we perform scrolling, we should correct "to" argument accordingly root.on('scroll', function(event) {
 var scrolled = root[0].scrollTop;
 scope.$apply(function() {
 scope.to = scrolled/attrs.sens;
 });
 });
 }
 };
 });

HTML用法:

<trng-repeat="item in vm.array | limitTo : 10 : vm.to"><td>{{item.name}}</td><td>{{item.age}}</td></tr><smart-scrollsens='10'limit='10'height='400'length='{{vm.array.length}}'to='vm.to'></smart-scroll>

让我们考虑参数:

  • 感知器- 这里参数与滚动敏感度相对,因此 1表示非常大的灵敏度。
  • 限制- 部分的大小,limitTolimit 部分
  • height - root 指令的简单对应html样式属性
  • 长度- array的长度( 被监视)
  • 到- 当前位置,从它的中部分启动( 已经更改),limitTobegin 部分

指令由两个div标记组成: 一个高度指定为参数且具有滚动能力和第二个位置的高度,后者位于 inside 之前。 root div的滚动位置有两种方式,数据绑定为参数: 滚动越大,参数parameter就会变得和相反。 滚动范围只依赖于内部div的高度,因为 root div的相应属性是常量值。 内部div的高度应该与 (array.length - limit) 换句话说,成比例 (scope.length - attrs.limit) 因为我们应该能够显示所有的记录,我们也提供非常重要和严格的按照: * 1 pixelOfScrolling = 1记录,to =ScrollPosition/(sens * 1 pixelOfScrolling) i.e. scope.to = scrolled/attrs.sens

那么内部div的高度调节滚动范围,它与 array.length的大小和 root div的滚动位置成比例,div的连接部分应该显示记录的哪部分。

我创建了所有这些代码的示例: 在这个例子中,我还在 array 上添加了过滤器,所以你不仅可以显示原始 array的某些部分,而且还可以从过滤过的条件中。 把它们组合起来是非常舒适的。

我将重现这个例子:

HTML:

<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"/><scriptsrc="https://code.jquery.com/jquery-3.1.1.min.js"integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="crossorigin="anonymous"></script><linkrel="stylesheet"href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"crossorigin="anonymous"><scriptsrc="//code.angularjs.org/snapshot/angular.min.js"></script><scriptsrc="app.js"></script></head><bodyng-app="app"><divng-controller="MyController as vm"><divclass="row"><divclass="col-sm-8"><divclass="form-group"><label>Search</label><inputclass="form-control"ng-model="vm.search"/></div></div><divclass="col-sm-2"><divclass="form-group"><label>&nbsp;</label><buttontype="button"class="btn btn-success col-sm-12"ng-click="vm.add()">Add to Top</button></div></div></div><divclass='row'><divclass="col-sm-10"><tableclass="table table-bordered"style="margin-bottom:0"><thead><tr><th>Name</th><th>Age</th><th></th></tr></thead><tbodyng-init="vm.to=0"><trng-repeat="item in vm.getItems() | limitTo : 10 : vm.to"ng-style='{"background-color": item.add?"#ccffcc" :"white"}'><td>{{item.name}}</td><td>{{item.age}}</td><td><ang-click="vm.removeItem(item)"href='#'>X</a></td></tr></tbody><tr><th>Total:</th><thcolspan='2'>{{vm.quantity}}</th></tr></table></div><divclass="col-sm-1"style="margin-top:0;padding-left: 0"><smart-scrollsens='10'limit='10'height='400'length='{{vm.quantity}}'to='vm.to'></smart-scroll></div></div></div></body></html

JavaScript:

(function(angular) {
 'use strict';
 var myApp = angular.module('app', []);
 myApp.controller('MyController', ['$scope', '$filter', function($scope, $filter) {
 var self = this;
 self.filter = $filter('filter');
 self.items = [];
 self.quantity = 50000;
 for (var i = 0; i <self.quantity; i++)
 self.items.push({
 name: 'Name' + i,
 age: i + 1 });
 self.getItems = function() {
 var out = self.filter(self.items, {name : self.search});
 self.quantity = out.length;
 return out;
 };
 self.removeItem = function(item) {
 self.items.splice(self.items.indexOf(item), 1);
 };
 self.add = function() {
 self.items.unshift({
 name: 'Name' + self.items.length,
 age: i + self.items.length,
 add: true });
 };
 }]).directive("smartScroll", function() {
 //directive's code is already presented 上面 });
})(window.angular)

结语

在本文中,我展示了如何在 ng-repeat 使用大迭代 array 时解决性能降低问题。 解决方案是基于想法显示和渲染,只对这里 array的用户部分显示,而不是整个。 这个目标可以通过使用简单的与AngularJS功能的滚动来归档: 以为代价,以自定义指令实现,滚动位置反映为 array 索引,它的上边框是显示的portion(window)的上边框。


相关文章