mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(collections): clean up UniqueSelectionDispatcher listeners on destroy (#9673)
* Clears out all of the registered listeners in the `UniqueSelectionDispatcher` when the module is unloaded to avoid potential memory leaks due to references inside the listeners. * Cleans up the unit test setup for the dispatcher to align it with the rest of the project.
This commit is contained in:
committed by
tinayuangao
parent
efb03c9ec8
commit
26b0635d1f
@@ -2,31 +2,36 @@ import {UniqueSelectionDispatcher} from './unique-selection-dispatcher';
|
||||
|
||||
|
||||
describe('Unique selection dispatcher', () => {
|
||||
let dispatcher: UniqueSelectionDispatcher;
|
||||
|
||||
describe('register', () => {
|
||||
it('once unregistered the listener must not be called on notify', (done) => {
|
||||
let dispatcher: UniqueSelectionDispatcher = new UniqueSelectionDispatcher();
|
||||
let called = false;
|
||||
beforeEach(() => dispatcher = new UniqueSelectionDispatcher());
|
||||
|
||||
// Register first listener
|
||||
dispatcher.listen(() => {
|
||||
called = true;
|
||||
});
|
||||
it('should notify registered listeners', () => {
|
||||
const spy = jasmine.createSpy('listen handler');
|
||||
|
||||
// Register a listener
|
||||
let deregisterFn = dispatcher.listen(() => {
|
||||
done.fail('Should not be called');
|
||||
});
|
||||
dispatcher.listen(spy);
|
||||
dispatcher.notify('id', 'name');
|
||||
|
||||
// Unregister
|
||||
deregisterFn();
|
||||
expect(spy).toHaveBeenCalledWith('id', 'name');
|
||||
});
|
||||
|
||||
// Call registered listeners
|
||||
dispatcher.notify('testId', 'testName');
|
||||
it('should not notify unregistered listeners', () => {
|
||||
const spy = jasmine.createSpy('listen handler');
|
||||
const unregister = dispatcher.listen(spy);
|
||||
|
||||
expect(called).toBeTruthy('Registered listener must be called.');
|
||||
unregister();
|
||||
dispatcher.notify('id', 'name');
|
||||
|
||||
done();
|
||||
});
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should remove all listeners when destroyed', () => {
|
||||
const spy = jasmine.createSpy('listen handler');
|
||||
dispatcher.listen(spy);
|
||||
|
||||
dispatcher.ngOnDestroy();
|
||||
dispatcher.notify('id', 'name');
|
||||
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Injectable, Optional, SkipSelf} from '@angular/core';
|
||||
import {Injectable, Optional, SkipSelf, OnDestroy} from '@angular/core';
|
||||
|
||||
|
||||
// Users of the Dispatcher never need to see this type, but TypeScript requires it to be exported.
|
||||
@@ -22,7 +22,7 @@ export type UniqueSelectionDispatcherListener = (id: string, name: string) => vo
|
||||
* less error-prone if they are simply passed through when the events occur.
|
||||
*/
|
||||
@Injectable()
|
||||
export class UniqueSelectionDispatcher {
|
||||
export class UniqueSelectionDispatcher implements OnDestroy {
|
||||
private _listeners: UniqueSelectionDispatcherListener[] = [];
|
||||
|
||||
/**
|
||||
@@ -48,6 +48,10 @@ export class UniqueSelectionDispatcher {
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this._listeners = [];
|
||||
}
|
||||
}
|
||||
|
||||
/** @docs-private */
|
||||
|
||||
Reference in New Issue
Block a user