Scrubbing of detached DOM elements, prevents memory leaks (#5265)

* Scrubbing of detached DOM elements, prevents memory leaks and fixes #5263

* Make linter happy
This commit is contained in:
Iván Sánchez Ortega 2017-02-02 10:57:57 +01:00 committed by Per Liedman
parent 5603a87c70
commit 14c5f1602c
8 changed files with 59 additions and 12 deletions

View File

@ -161,6 +161,11 @@ Map.include({
},
_clearControlPos: function () {
for (var i in this._controlCorners) {
DomUtil.remove(this._controlCorners[i]);
}
DomUtil.remove(this._controlContainer);
delete this._controlCorners;
delete this._controlContainer;
}
});

View File

@ -23,7 +23,6 @@ export var _pointersCount = 0;
// ref http://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890
export function addPointerListener(obj, type, handler, id) {
if (type === 'touchstart') {
_addPointerStart(obj, handler, id);

View File

@ -37,6 +37,8 @@ export function on(obj, types, fn, context) {
return this;
}
var eventsKey = '_leaflet_events';
// @function off(el: HTMLElement, types: String, fn: Function, context?: Object): this
// Removes a previously added listener function. If no function is specified,
// it will remove all the listeners of that particular DOM event from the element.
@ -46,25 +48,30 @@ export function on(obj, types, fn, context) {
// @alternative
// @function off(el: HTMLElement, eventMap: Object, context?: Object): this
// Removes a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
// @alternative
// @function off(el: HTMLElement): this
// Removes all known event listeners
export function off(obj, types, fn, context) {
if (typeof types === 'object') {
for (var type in types) {
removeOne(obj, type, types[type], fn);
}
} else {
} else if (types) {
types = Util.splitWords(types);
for (var i = 0, len = types.length; i < len; i++) {
removeOne(obj, types[i], fn, context);
}
} else {
for (var j in obj[eventsKey]) {
removeOne(obj, j, obj[eventsKey][j]);
}
delete obj[eventsKey];
}
return this;
}
var eventsKey = '_leaflet_events';
function addOne(obj, type, fn, context) {
var id = type + Util.stamp(fn) + (context ? '_' + Util.stamp(context) : '');

View File

@ -67,6 +67,13 @@ export var Canvas = Renderer.extend({
this._ctx = container.getContext('2d');
},
_destroyContainer: function () {
delete this._ctx;
L.DomUtil.remove(this._container);
L.DomEvent.off(this._container);
delete this._container;
},
_updatePaths: function () {
if (this._postponeUpdatePaths) { return; }

View File

@ -58,8 +58,8 @@ export var Renderer = Layer.extend({
},
onRemove: function () {
DomUtil.remove(this._container);
this.off('update', this._updatePaths, this);
this._destroyContainer();
},
getEvents: function () {

View File

@ -61,6 +61,13 @@ export var SVG = Renderer.extend({
this._container.appendChild(this._rootGroup);
},
_destroyContainer: function () {
L.DomUtil.remove(this._container);
L.DomEvent.off(this._container);
delete this._container;
delete this._rootGroup;
},
_onZoomStart: function () {
// Drag-then-pinch interactions might mess up the center and zoom.
// In this case, the easiest way to prevent this is re-do the renderer

View File

@ -716,9 +716,18 @@ export var Map = Evented.extend({
this.fire('unload');
}
for (var i in this._layers) {
var i;
for (i in this._layers) {
this._layers[i].remove();
}
for (i in this._panes) {
L.DomUtil.remove(this._panes[i]);
}
this._layers = [];
this._panes = [];
delete this._mapPane;
delete this._renderer;
return this;
},
@ -1507,12 +1516,12 @@ export var Map = Evented.extend({
this.on('zoomanim', function (e) {
var prop = DomUtil.TRANSFORM,
transform = proxy.style[prop];
transform = this._proxy.style[prop];
DomUtil.setTransform(proxy, this.project(e.center, e.zoom), this.getZoomScale(e.zoom, 1));
DomUtil.setTransform(this._proxy, this.project(e.center, e.zoom), this.getZoomScale(e.zoom, 1));
// workaround for case when transform is the same and so transitionend event is not fired
if (transform === proxy.style[prop] && this._animatingZoom) {
if (transform === this._proxy.style[prop] && this._animatingZoom) {
this._onZoomTransitionEnd();
}
}, this);
@ -1520,8 +1529,15 @@ export var Map = Evented.extend({
this.on('load moveend', function () {
var c = this.getCenter(),
z = this.getZoom();
DomUtil.setTransform(proxy, this.project(c, z), this.getZoomScale(z, 1));
DomUtil.setTransform(this._proxy, this.project(c, z), this.getZoomScale(z, 1));
}, this);
this._on('unload', this._destroyAnimProxy, this);
},
_destroyAnimProxy: function () {
L.DomUtil.remove(this._proxy);
delete this._proxy;
},
_catchTransitionEnd: function (e) {

View File

@ -25,6 +25,7 @@ export var BoxZoom = Handler.extend({
this._map = map;
this._container = map._container;
this._pane = map._panes.overlayPane;
map.on('unload', this._destroy, this);
},
addHooks: function () {
@ -39,6 +40,11 @@ export var BoxZoom = Handler.extend({
return this._moved;
},
_destroy: function () {
L.DomUtil.remove(this._pane);
delete this._pane;
},
_resetState: function () {
this._moved = false;
},