утечки памяти javascript - PullRequest
       7

утечки памяти javascript

18 голосов
/ 23 февраля 2010

Я использую jquery и делаю что-то вроде этого

DOM * * 1004

<div id="parent"></div>

JS

var _doSomeThing = function()
{
    //some codes
}

$(function()
{
    // appending div and binding methods to span
    $('#parent').append('<span>1</span>');
    $('#parent').append('<span>2</span>');
    $('#parent span').bind('click', _doSomeThing);
});

function _clearDiv()
{
    //clear div
    $('#parent').html('');
}

//sometime in future, call clear div
_clearDiv();

Теперь мой вопрос: приводят ли события привязки к DOM, а затем просто удаление элементов из DOM приводит к утечке памяти?

Если да, как решить эту проблему?

Ответы [ 5 ]

19 голосов
/ 24 февраля 2010

Метод jQuery html пытается предотвратить утечки памяти, удаляя обработчики событий для любых элементов, которые удаляются в результате вызова .html('') для объекта jQuery.

Из источника 1.4.2

html: function( value ) {
    if ( value === undefined ) {
        return this[0] && this[0].nodeType === 1 ?
        this[0].innerHTML.replace(rinlinejQuery, "") :
            null;
    } 
    // See if we can take a shortcut and just use innerHTML
    // THE RELEVANT PART
    else if ( typeof value === "string" && !rnocache.test( value ) &&
        (jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
        !wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {

        value = value.replace(rxhtmlTag, fcloseTag);

        try {
            for ( var i = 0, l = this.length; i < l; i++ ) {
                // Remove element nodes and prevent memory leaks
               if ( this[i].nodeType === 1 ) {
                   jQuery.cleanData( this[i].getElementsByTagName("*") );
                   this[i].innerHTML = value;
                }
            }

        // If using innerHTML throws an exception, use the fallback method
        } 
        catch(e) {
            this.empty().append( value );
        }
    } 
    else if ( jQuery.isFunction( value ) ) {
        this.each(function(i){
            var self = jQuery(this), old = self.html();
            self.empty().append(function(){
                return value.call( this, i, old );
            });
        });

    }
    else {
        this.empty().append( value );
    }
    return this;
}

Мы видим, что вызывается функция jQuery.cleanData(). Вот источник для этого

cleanData: function( elems ) {
    var data, id, cache = jQuery.cache,
        special = jQuery.event.special,
        deleteExpando = jQuery.support.deleteExpando;

    for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
        id = elem[ jQuery.expando ];

        if ( id ) {
            data = cache[ id ];

            if ( data.events ) {
                for ( var type in data.events ) {
                    if ( special[ type ] ) {
                        jQuery.event.remove( elem, type );

                    } else {
                        removeEvent( elem, type, data.handle );
                    }
                }
            }

            if ( deleteExpando ) {
                delete elem[ jQuery.expando ];

            } else if ( elem.removeAttribute ) {
                elem.removeAttribute( jQuery.expando );
            }

            delete cache[ id ];
        }
    }
}

В объекте jQuery.cache выполняется поиск любых свойств типа события в свойстве объекта событий объекта данных, относящегося к каждому элементу, который будет удален при вызове .html(''), и удаляется их.

Чтобы в основном объяснить, как работает стандартная привязка событий, когда функция связана как обработчик с событием, вызванным в элементе с использованием jQuery, объект данных добавляется в качестве свойства к объекту jQuery.cache. Этот объект данных содержит объект свойства событий, для которого будет создано свойство с именем, соответствующим типу события, с которым вы хотите связать функцию-обработчик событий. это свойство будет содержать массив функций, которые должны вызываться при возникновении события в элементе, поэтому функция обработчика события добавляется в этот массив. Если это первая функция-обработчик события для рассматриваемого типа события и элемента, то функция jQuery.event.handle с вызовом для применения (с использованием элемента в качестве контекста, так что this в контексте выполнения функции будет ссылаться на элемент) зарегистрирован в браузере с помощью addEventListener/attachEvent.

Когда событие вызывается, функция jQuery.event.handle вызывает все функции в массиве для свойства объекта свойства events объекта данных, соответствующего типу события и элементу, для которого было инициировано событие.

Итак, в итоге, html('') не должно вызывать утечек памяти, поскольку существует ряд защитных мер для их предотвращения.

2 голосов
/ 23 февраля 2010

Да, потому что jQuery поддерживает список подключенных обработчиков событий, чтобы упростить их открепление и явно отцепить их для вас при выгрузке страницы (что помогает избежать более серьезной утечки памяти в IE) (Как и Prototype, не могу говорить за других библиотек.) Решение состоит в том, чтобы отцепить их перед удалением элементов (либо напрямую, либо через empty).

2 голосов
/ 23 февраля 2010

Не могу прокомментировать проблему утечки, но вы можете просто использовать .empty() вместо .html(''). Таким образом вы очистите innerHTML и удалите все связанные обработчики событий.

1 голос
/ 23 февраля 2010

Вы всегда можете использовать $('#parent span').unbind(); просто для уверенности

0 голосов
/ 23 февраля 2010

Поскольку вы постоянно ссылаетесь на $ ('# parent'), вы должны создать ссылку на этот объект в глобальной области видимости, чтобы jQuery не постоянно искал объект при каждом запросе. Делая это, вы по сути кешируете ссылку на объект, что значительно сократит использование памяти.

_parent = $('#parent');

...

function(){ _parent.append('<span>1</span>'); }

Изменить: я взял этот совет из этой статьи на Правила производительности jQuery

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...