From 7e996a650e4421622659ccce2c23f24cc25da8dd Mon Sep 17 00:00:00 2001 From: crisbeto Date: Thu, 20 Sep 2018 23:10:47 +0200 Subject: [PATCH] refactor(grid-list): avoid recreating tile coordinator for every change detection Currently we recreate the `TileCoordinator` and throw out the old one on every change detection run. These changes reuse a single `TileCoordinator` and update it instead, which ends up shaving off a couple of milliseconds off each layout and reduces the amount of objects that need to be garbage collected. **Note:** this is a breaking API change for the `TileCoordinator`, however it isn't exported through `material/grid-list`. --- src/lib/grid-list/grid-list.ts | 11 ++++++++++- src/lib/grid-list/tile-coordinator.ts | 18 +++++++++++++----- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/lib/grid-list/grid-list.ts b/src/lib/grid-list/grid-list.ts index fcac60396582..73828c08b8d9 100644 --- a/src/lib/grid-list/grid-list.ts +++ b/src/lib/grid-list/grid-list.ts @@ -47,6 +47,9 @@ export class MatGridList implements OnInit, AfterContentChecked { /** Number of columns being rendered. */ private _cols: number; + /** Used for determiningthe position of each tile in the grid. */ + private _tileCoordinator: TileCoordinator; + /** * Row height value passed in by user. This can be one of three types: * - Number value (ex: "100px"): sets a fixed row height to that value @@ -135,8 +138,14 @@ export class MatGridList implements OnInit, AfterContentChecked { /** Computes and applies the size and position for all children grid tiles. */ private _layoutTiles(): void { - const tracker = new TileCoordinator(this.cols, this._tiles); + if (!this._tileCoordinator) { + this._tileCoordinator = new TileCoordinator(this._tiles); + } + + const tracker = this._tileCoordinator; const direction = this._dir ? this._dir.value : 'ltr'; + + this._tileCoordinator.update(this.cols); this._tileStyler.init(this.gutterSize, tracker, this.cols, direction); this._tiles.forEach((tile, index) => { diff --git a/src/lib/grid-list/tile-coordinator.ts b/src/lib/grid-list/tile-coordinator.ts index 7ea74cd4cd87..e638b6492e15 100644 --- a/src/lib/grid-list/tile-coordinator.ts +++ b/src/lib/grid-list/tile-coordinator.ts @@ -44,7 +44,7 @@ export class TileCoordinator { * Ex: A list with 1 row that contains a tile with rowspan 2 will have a total rowspan of 2. */ get rowspan() { - let lastRowMax = Math.max(...this.tracker); + const lastRowMax = Math.max(...this.tracker); // if any of the tiles has a rowspan that pushes it beyond the total row count, // add the difference to the rowcount return lastRowMax > 1 ? this.rowCount + lastRowMax - 1 : this.rowCount; @@ -53,17 +53,25 @@ export class TileCoordinator { /** The computed (row, col) position of each tile (the output). */ positions: TilePosition[]; - constructor(numColumns: number, tiles: QueryList) { + constructor(private _tiles: QueryList) {} + + /** + * Updates the tile positions. + * @param numColumns Amount of columns in the grid. + */ + update(numColumns: number) { + this.columnIndex = 0; + this.rowIndex = 0; + this.tracker = new Array(numColumns); this.tracker.fill(0, 0, this.tracker.length); - - this.positions = tiles.map(tile => this._trackTile(tile)); + this.positions = this._tiles.map(tile => this._trackTile(tile)); } /** Calculates the row and col position of a tile. */ private _trackTile(tile: MatGridTile): TilePosition { // Find a gap large enough for this tile. - let gapStartIndex = this._findMatchingGap(tile.colspan); + const gapStartIndex = this._findMatchingGap(tile.colspan); // Place tile in the resulting gap. this._markTilePosition(gapStartIndex, tile);