Fix #8545. Plug event handling memory leak in oldIE.

This commit is contained in:
Oleg 2012-04-04 21:17:01 -04:00 committed by Dave Methvin
parent 41056ab195
commit 203a168980
3 changed files with 29 additions and 20 deletions

View File

@ -6,6 +6,8 @@ var rbrace = /^(?:\{.*\}|\[.*\])$/,
jQuery.extend({ jQuery.extend({
cache: {}, cache: {},
deletedIds: [],
// Please use with caution // Please use with caution
uuid: 0, uuid: 0,
@ -59,7 +61,7 @@ jQuery.extend({
// Only DOM nodes need a new unique ID for each element since their data // Only DOM nodes need a new unique ID for each element since their data
// ends up in the global cache // ends up in the global cache
if ( isNode ) { if ( isNode ) {
elem[ internalKey ] = id = ++jQuery.uuid; elem[ internalKey ] = id = jQuery.deletedIds.pop() || ++jQuery.uuid;
} else { } else {
id = internalKey; id = internalKey;
} }
@ -212,6 +214,8 @@ jQuery.extend({
// We destroyed the cache and need to eliminate the expando on the node to avoid // We destroyed the cache and need to eliminate the expando on the node to avoid
// false lookups in the cache for entries that no longer exist // false lookups in the cache for entries that no longer exist
if ( isNode ) { if ( isNode ) {
jQuery.deletedIds.push( id );
// IE does not allow us to delete expando properties from nodes, // IE does not allow us to delete expando properties from nodes,
// nor does it have a removeAttribute function on Document nodes; // nor does it have a removeAttribute function on Document nodes;
// we must handle all of these cases // we must handle all of these cases

View File

@ -154,7 +154,7 @@ jQuery.event = {
var elemData = jQuery.hasData( elem ) && jQuery._data( elem ), var elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
t, tns, type, origType, namespaces, origCount, t, tns, type, origType, namespaces, origCount,
j, events, special, handle, eventType, handleObj; j, events, special, eventType, handleObj;
if ( !elemData || !(events = elemData.events) ) { if ( !elemData || !(events = elemData.events) ) {
return; return;
@ -213,14 +213,11 @@ jQuery.event = {
// Remove the expando if it's no longer used // Remove the expando if it's no longer used
if ( jQuery.isEmptyObject( events ) ) { if ( jQuery.isEmptyObject( events ) ) {
handle = elemData.handle; delete elemData.handle;
if ( handle ) {
handle.elem = null;
}
// removeData also checks for emptiness and clears the expando if empty // removeData also checks for emptiness and clears the expando if empty
// so use it instead of delete // so use it instead of delete
jQuery.removeData( elem, [ "events", "handle" ], true ); jQuery.removeData( elem, "events", true );
} }
}, },
@ -636,8 +633,17 @@ jQuery.removeEvent = document.removeEventListener ?
} }
} : } :
function( elem, type, handle ) { function( elem, type, handle ) {
var name = "on" + type;
if ( elem.detachEvent ) { if ( elem.detachEvent ) {
elem.detachEvent( "on" + type, handle );
// #8545, #7054, preventing memory leaks for custom events in IE6-8
// detachEvent needed property on element, by name of that event, to properly expose it to GC
if ( typeof elem[ name ] === "undefined" ) {
elem[ name ] = null;
}
elem.detachEvent( name, handle );
} }
}; };

View File

@ -811,13 +811,10 @@ jQuery.extend({
jQuery.removeEvent( elem, type, data.handle ); jQuery.removeEvent( elem, type, data.handle );
} }
} }
// Null the DOM reference to avoid IE6/7/8 leak (#7054)
if ( data.handle ) {
data.handle.elem = null;
}
} }
// Remove cache only if jQuery.event.remove was not removed it before
if ( cache[ id ] ) {
if ( deleteExpando ) { if ( deleteExpando ) {
delete elem[ jQuery.expando ]; delete elem[ jQuery.expando ];
@ -825,10 +822,12 @@ jQuery.extend({
elem.removeAttribute( jQuery.expando ); elem.removeAttribute( jQuery.expando );
} }
jQuery.deletedIds.push( id );
delete cache[ id ]; delete cache[ id ];
} }
} }
} }
}
}); });
})( jQuery ); })( jQuery );