В целом , в jQuery есть система, в которой к элементу присоединяется один обработчик, который сохраняет ссылку на элемент через замыкание.
Когда событие происходит с элементом, оновызывает более общий обработчик (jQuery.event.handle
) из контекста этого элемента, который передает полученный объект event
.
Этот обработчик анализирует событие, выполняет поиск элемента в jQuery.cache
через свойство jQuery1234567...
expando этого элемента и вызывает соответствующий обработчик (и), которые также хранятся взапись jQuery.cache
этого элемента.
В результате получается, что единственный обработчик, на самом деле прикрепленный к элементу, - это облегченный обработчик, который jQuery
сам создает и присоединяет.Поэтому это никогда не вызовет утечек памяти в IE из-за каких-либо циклических ссылок на элементы DOM .
Одна вещь, которую вы должны знает, что при использовании jQuery
для управления обработчиками событий ссылка only между элементом и его записью в jQuery.cache
является этим свойством expando.
Если у вас есть какой-то код, который выходит за пределы jQuery
для удаления элементов из DOM, то jQuery
не уведомляется об удалении связанных обработчиков и других данных из jQuery.cache
, вызывая утечку собственной памяти, которая не ограничивается старойверсии IE.
Итак, если у вас есть раздел HTML
, к которому подключены обработчики через jQuery
, и вы делаете что-то вроде этого:
element_container.innerHTML = '';
... теперь любые записи в jQuery.cache
которые относятся к удаленным элементам, являются осиротевшими и, вероятно, будут существовать до тех пор, пока окно браузера остается открытым.
Так что, если вы используете jQuery
для управления привязкой событий, при удалении обязательно оставайтесь в APIэлементы, так что jQuery
может управлять и очищать jQuery.cache
при необходимости.
РЕДАКТИРОВАТЬ: Я перевернул обработчики.Хотя в целом та же концепция.
/*
Here we bind 4 handlers to the same element.
*/
var elem = $('#my_elem');
// This first call to .bind() binds a generic handler to `#my_elem`.
// Then it places the handler we passed in jQuery.cache.
elem.bind( 'click', function() { alert( 'click 1' ); } );
// Generic handler already exists, so these handlers are
// just added to jQuery.cache.
elem.bind( 'click', function() { alert( 'click 2' ); } );
elem.bind( 'mouseenter', function() { alert( 'mouseenter 1' ); } );
elem.bind( 'mouseleave', function() { alert( 'mouseleave 1' ); } );
/*
This is a simplified example of the binding of the generic handler. Notice
that it actually invokes an internal function.
*/
elem[0].addEventListener( 'click', function( e ) {
_internal_handler.apply( elem, arguments );
}, false);
/*
This is a simplified example of the internal function.
*/
_internal_handler( e ) {
// Find out the type of event, like "click", or whatever
var event_type = e.type;
// Get this element's data from jQuery.cache
var data = jQuery.data( this );
// If data was found...
if( data ) {
// ...get the "events" stored in the element's data
var events = data.events;
// If events were found, and events has the current type of event...
if( events && events[ event_type ] ) {
// ...then data.events[ event_type ] will give us the Array of
// handlers for that event type, so iterate the Array,
// and fire the handlers.
for( var i = 0; i < events[ event_type ]; i++; ) {
// handler invoked
events[ event_type ][ i ].call( this, e );
}
}
}
}
Это, конечно, экстремальное упрощение кода, но в целом показывает, что происходит.