jQuery: memory leaks

Думаю, для многих не секрет, что при назначении обработчика события, в `jQuery.cache` добавляется ссылка на этот элемент. И если вовремя не снять слушателя, это приведет к утечке памяти.

Чаще всего, такая проблема возникает, если работать с DOM напрямую, минуя методы jQuery, например, используя innerHTML.         

<div id=”layout”>
        <button>click me</button>
</div>

<script>
        // Вешаем обработчик
        $(‘button’).click(function (){
                    // Загружаем какой-то html
                    $.get(‘/layout’, function (content){
                                // Заменяем текущие содержание на новое
                                $(‘#layout’).prop(‘innerHTML’, content );
                    });
});
</script>

В примере содержимое `#layout` заменяется и ссылка на элемент `button` «застревает» в `jQuery.cache`. Если перед заменой, вызвать `$(‘#layout’).empty()`, то утечки не будет.

Причина использования `innerHTML` в медленной работе jQuery методов. Случается, что при вызове $.fn.html/append (и подобных), браузер подвисает намертво.

Однако использование методов jQuery, для работы с DOM, не гарантирует, что утечки не будет.

Проблемы можно получить даже в достаточно просто коде:

$(new Image)
.attr(“src”, “http://domain.com/fail.png”)

.one(“load”, function (){ /*__*/ })
;

На первый взгляд, код безопасен, но происходит ошибка и событие `load` не отрабатывает — код “потек”.

В полной мере, проблему можно прочувствовать при разработке одностраничного приложения, где даже незначительная утечка, со временем приводит к краху браузера.

Чтобы избежать таких ситуаций, я разработал маленькую утилиту, которая следит за объектом `jQuery.cache` и элементами, находящимися в нем. Если элемент не находиться в DOM, то он считается “утёкшим”.

Утилита содержит всего четыре метода:

  • $.leaks.get() — получить список “утёкших” элементов;
  • $.leaks.watch() — начать слежение за утечками, если они возникают в console будет выведено количество “утёкших” элементов (“jQuery leaks: XX”);
  • $.leaks.unwatch() — остановить слежение;
  • $.leaks.remove() — удалить “утечки” (вызов `$.clearData($.leaks.get())`).


Надеюсь данная утилита будет вам полезна.

Исходник — jquery.leaks.js

2 комментария:

  1. Вот поэтому я и использую

    $('#layout').on('click', 'button', ...);

    который не течет

    ОтветитьУдалить
    Ответы
    1. Дело не в этом, даже в этот код может потечь. + повсеместное использование делегатов, чревато тормозами, всему своё место.

      Удалить