Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf(tree): leaking reference through mostRecentTreeNode #12334

Merged
merged 1 commit into from
Jul 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/cdk/tree/tree.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {TreeControl} from './control/tree-control';
import {FlatTreeControl} from './control/flat-tree-control';
import {NestedTreeControl} from './control/nested-tree-control';
import {CdkTreeModule} from './index';
import {CdkTree} from './tree';
import {CdkTree, CdkTreeNode} from './tree';
import {getTreeControlFunctionsMissingError} from './tree-errors';


Expand All @@ -35,6 +35,20 @@ describe('CdkTree', () => {
}).compileComponents();
}

it('should clear out the `mostRecentTreeNode` on destroy', () => {
configureCdkTreeTestingModule([SimpleCdkTreeApp]);
const fixture = TestBed.createComponent(SimpleCdkTreeApp);
fixture.detectChanges();

// Cast the assertions to a boolean to avoid Jasmine going into an
// infinite loop when stringifying the object, if the test starts failing.
expect(!!CdkTreeNode.mostRecentTreeNode).toBe(true);

fixture.destroy();

expect(!!CdkTreeNode.mostRecentTreeNode).toBe(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just toBeFalsy or toBeNull here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left a comment about it a few lines about. Using .toBeFalsy will cause Jasmine to go into an infinite loop, if this test ever starts failing, because it tries to stringify an object with circular references.

});

describe('flat tree', () => {
describe('should initialize', () => {
let fixture: ComponentFixture<SimpleCdkTreeApp>;
Expand Down
8 changes: 7 additions & 1 deletion src/cdk/tree/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ export class CdkTree<T>
'class': 'cdk-tree-node',
},
})
export class CdkTreeNode<T> implements FocusableOption, OnDestroy {
export class CdkTreeNode<T> implements FocusableOption, OnDestroy {
/**
* The most recently created `CdkTreeNode`. We save it in static variable so we can retrieve it
* in `CdkTree` and set the data to it.
Expand Down Expand Up @@ -328,6 +328,12 @@ export class CdkTreeNode<T> implements FocusableOption, OnDestroy {
}

ngOnDestroy() {
// If this is the last tree node being destroyed,
// clear out the reference to avoid leaking memory.
if (CdkTreeNode.mostRecentTreeNode === this) {
CdkTreeNode.mostRecentTreeNode = null;
}

this._destroyed.next();
this._destroyed.complete();
}
Expand Down