Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit b3133f0

Browse files
devversionkara
authored andcommitted
test(virtual-repeat): reduce memory consumption significant (#9659)
* The virtual repeat tests right now create two times more than 1.5 Million items at same time (2 million and 1.6 million). * This is extremly filling the available memory (especially on Saucelabs) and potentionally slows / crashes the test suite. References #9560
1 parent 9d434e3 commit b3133f0

File tree

3 files changed

+52
-24
lines changed

3 files changed

+52
-24
lines changed

src/components/virtualRepeat/virtual-repeater.js

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,6 @@ function virtualRepeatContainerTemplate($element) {
8080
'</div></div>';
8181
}
8282

83-
/**
84-
* Maximum size, in pixels, that can be explicitly set to an element. The actual value varies
85-
* between browsers, but IE11 has the very lowest size at a mere 1,533,917px. Ideally we could
86-
* *compute* this value, but Firefox always reports an element to have a size of zero if it
87-
* goes over the max, meaning that we'd have to binary search for the value.
88-
* @const {number}
89-
*/
90-
var MAX_ELEMENT_SIZE = 1533917;
91-
9283
/**
9384
* Number of additional elements to render above and below the visible area inside
9485
* of the virtual repeat container. A higher number results in less flicker when scrolling
@@ -98,8 +89,8 @@ var MAX_ELEMENT_SIZE = 1533917;
9889
var NUM_EXTRA = 3;
9990

10091
/** @ngInject */
101-
function VirtualRepeatContainerController(
102-
$$rAF, $mdUtil, $parse, $rootScope, $window, $scope, $element, $attrs) {
92+
function VirtualRepeatContainerController($$rAF, $mdUtil, $mdConstant, $parse, $rootScope, $window, $scope,
93+
$element, $attrs) {
10394
this.$rootScope = $rootScope;
10495
this.$scope = $scope;
10596
this.$element = $element;
@@ -125,6 +116,8 @@ function VirtualRepeatContainerController(
125116
this.offsetSize = parseInt(this.$attrs.mdOffsetSize, 10) || 0;
126117
/** @type {?string} height or width element style on the container prior to auto-shrinking. */
127118
this.oldElementSize = null;
119+
/** @type {!number} Maximum amount of pixels allowed for a single DOM element */
120+
this.maxElementPixels = $mdConstant.ELEMENT_MAX_PIXELS;
128121

129122
if (this.$attrs.mdTopIndex) {
130123
/** @type {function(angular.Scope): number} Binds to topIndex on Angular scope */
@@ -262,26 +255,26 @@ VirtualRepeatContainerController.prototype.sizeScroller_ = function(size) {
262255
// If the size falls within the browser's maximum explicit size for a single element, we can
263256
// set the size and be done. Otherwise, we have to create children that add up the the desired
264257
// size.
265-
if (size < MAX_ELEMENT_SIZE) {
258+
if (size < this.maxElementPixels) {
266259
this.sizer.style[dimension] = size + 'px';
267260
} else {
268261
this.sizer.style[dimension] = 'auto';
269262
this.sizer.style[crossDimension] = 'auto';
270263

271264
// Divide the total size we have to render into N max-size pieces.
272-
var numChildren = Math.floor(size / MAX_ELEMENT_SIZE);
265+
var numChildren = Math.floor(size / this.maxElementPixels);
273266

274267
// Element template to clone for each max-size piece.
275268
var sizerChild = document.createElement('div');
276-
sizerChild.style[dimension] = MAX_ELEMENT_SIZE + 'px';
269+
sizerChild.style[dimension] = this.maxElementPixels + 'px';
277270
sizerChild.style[crossDimension] = '1px';
278271

279272
for (var i = 0; i < numChildren; i++) {
280273
this.sizer.appendChild(sizerChild.cloneNode(false));
281274
}
282275

283276
// Re-use the element template for the remainder.
284-
sizerChild.style[dimension] = (size - (numChildren * MAX_ELEMENT_SIZE)) + 'px';
277+
sizerChild.style[dimension] = (size - (numChildren * this.maxElementPixels)) + 'px';
285278
this.sizer.appendChild(sizerChild);
286279
}
287280
};

src/components/virtualRepeat/virtual-repeater.spec.js

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
describe('<md-virtual-repeat>', function() {
2-
beforeEach(module('material.components.virtualRepeat'));
2+
3+
var MAX_ELEMENT_PIXELS = 10000;
4+
5+
beforeEach(module('material.components.virtualRepeat', function($provide) {
6+
/*
7+
* Overwrite the $mdConstant ELEMENT_MAX_PIXELS property, because for testing it requires too much
8+
* memory and crashes the tests sometimes.
9+
*/
10+
$provide.decorator('$mdConstant', function($delegate) {
11+
12+
$delegate.ELEMENT_MAX_PIXELS = MAX_ELEMENT_PIXELS;
13+
14+
return $delegate;
15+
})
16+
}));
317

418
var VirtualRepeatController = { NUM_EXTRA : 3 };
519

@@ -303,11 +317,9 @@ describe('<md-virtual-repeat>', function() {
303317
});
304318

305319
it('should cap individual element size for the sizer in large item sets', function() {
306-
// Copy max element size because we don't have a good way to reference it.
307-
var maxElementSize = 1533917;
320+
// Create a larger number of items than will fit in one maximum element size.
321+
var numItems = MAX_ELEMENT_PIXELS / ITEM_SIZE + 1;
308322

309-
// Create a much larger number of items than will fit in one maximum element size.
310-
var numItems = 2000000;
311323
createRepeater();
312324
scope.items = createItems(numItems);
313325
scope.$apply();
@@ -319,17 +331,18 @@ describe('<md-virtual-repeat>', function() {
319331

320332
// Expect that sizer only adds as many children as it needs to.
321333
var numChildren = sizer[0].childNodes.length;
322-
expect(numChildren).toBe(Math.ceil(numItems * ITEM_SIZE / maxElementSize));
334+
expect(numChildren).toBe(Math.ceil(numItems * ITEM_SIZE / MAX_ELEMENT_PIXELS));
323335

324336
// Expect that every child of sizer does not exceed the maximum element size.
325337
for (var i = 0; i < numChildren; i++) {
326-
expect(sizer[0].childNodes[i].offsetHeight).toBeLessThan(maxElementSize + 1);
338+
expect(sizer[0].childNodes[i].offsetHeight).toBeLessThan(MAX_ELEMENT_PIXELS + 1);
327339
}
328340
});
329341

330342
it('should clear scroller if large set of items is filtered to much smaller set', function() {
331-
// Create a much larger number of items than will fit in one maximum element size.
332-
var numItems = 2000000;
343+
// Create a larger number of items than will fit in one maximum element size.
344+
var numItems = MAX_ELEMENT_PIXELS / ITEM_SIZE + 1;
345+
333346
createRepeater();
334347
scope.items = createItems(numItems);
335348
scope.$apply();
@@ -339,6 +352,10 @@ describe('<md-virtual-repeat>', function() {
339352
// We expect the offset to be close to the exact height, because on IE there are some deviations.
340353
expect(sizer[0].offsetHeight).toBeCloseTo(numItems * ITEM_SIZE, -1);
341354

355+
// Expect the sizer to have children, because the the children are necessary to not exceed the maximum
356+
// size of a DOM element.
357+
expect(sizer[0].children.length).not.toBe(0);
358+
342359
// Now that the sizer is really big, change the the number of items to be very small.
343360
numItems = 2;
344361
scope.items = createItems(numItems);

src/core/util/constant.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ function MdConstantFactory($sniffer, $window, $document) {
4141
return (NAVIGATION_KEYS.indexOf(e.keyCode) != -1);
4242
},
4343

44+
/**
45+
* Maximum size, in pixels, that can be explicitly set to an element. The actual value varies
46+
* between browsers, but IE11 has the very lowest size at a mere 1,533,917px. Ideally we could
47+
* compute this value, but Firefox always reports an element to have a size of zero if it
48+
* goes over the max, meaning that we'd have to binary search for the value.
49+
*/
50+
ELEMENT_MAX_PIXELS: 1533917,
51+
52+
/**
53+
* Common Keyboard actions and their associated keycode.
54+
*/
4455
KEY_CODE: {
4556
COMMA: 188,
4657
SEMICOLON : 186,
@@ -59,6 +70,11 @@ function MdConstantFactory($sniffer, $window, $document) {
5970
BACKSPACE: 8,
6071
DELETE: 46
6172
},
73+
74+
/**
75+
* Vendor prefixed CSS properties to be used to support the given functionality in older browsers
76+
* as well.
77+
*/
6278
CSS: {
6379
/* Constants */
6480
TRANSITIONEND: 'transitionend' + (isWebkit ? ' webkitTransitionEnd' : ''),
@@ -74,6 +90,7 @@ function MdConstantFactory($sniffer, $window, $document) {
7490
ANIMATION_TIMING: vendorProperty('animationTimingFunction'),
7591
ANIMATION_DIRECTION: vendorProperty('animationDirection')
7692
},
93+
7794
/**
7895
* As defined in core/style/variables.scss
7996
*
@@ -97,6 +114,7 @@ function MdConstantFactory($sniffer, $window, $document) {
97114
'portrait' : '(orientation: portrait)' ,
98115
'print' : 'print'
99116
},
117+
100118
MEDIA_PRIORITY: [
101119
'xl',
102120
'gt-lg',

0 commit comments

Comments
 (0)