2008-11-09 3 views
7

Я работаю над веб-приложением, которое предназначено для отображения множества данных, которые периодически обновляются с помощью AJAX. Общий сценарий использования будет заключаться в том, что пользователь оставит его открытым весь день и время от времени заглядывает в него.Предотвращение утечек памяти AJAX

У меня возникла проблема, при которой площадь памяти браузеров медленно растет с течением времени. Это происходит как в Firefox, так и в IE 7 (хотя и не в Chrome). Через несколько часов это может привести к тому, что IE7 будет иметь размер ~ 200 МБ и FF3, чтобы иметь площадь около 400 МБ.

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

Я использую прототип для своих вызовов AJAX. Итак, я предполагаю, что есть проблема с обратным вызовом onSuccess, создающим эти утечки памяти.

Есть ли у кого-нибудь советы по предотвращению утечек памяти с прототипом/AJAX? Или какие-либо методы устранения этой проблемы?

EDIT: выяснилось, что проблема заключается в библиотеке js-графиков, которую я использую. Видно here.

ответ

10

Самое большое, что вы можете наблюдать за событиями, и то, как вы их назначаете.

Например, возьмем этот сценарий (так как вы не предоставили один):

<div id="ajaxResponseTarget"> 
    ... 
</div> 
<script type="text/javascript"> 
    $(someButton).observe('click', function() { 
     new Ajax.Updater($('ajaxResponseTarget'), someUrl, { 
      onSuccess: function() { 
       $$('#ajaxResponseTarget .someButtonClass').invoke('observe', 'click', function() { 
        ... 
       }); 
      } 
     }); 
    }); 
</script> 

Это создаст утечку памяти, потому что, когда #ajaxResponseTarget обновляется (внутренне, прототип будет использовать innerHTML) элементы с click события будут удалены из документа без удаления их событий. Во второй раз, когда вы нажмете someButton, у вас будет в два раза больше обработчиков событий, и сбор мусора не сможет удалить первый набор.

Способ избежать этого является использование событие делегации:

<div id="ajaxResponseTarget"> 
    ... 
</div> 
<script type="text/javascript"> 
    $('ajaxResponseTarget').observe('click', function(e) { 
     if(e.element().match('.someButtonClass')) { 
      ... 
     } 
    }); 
    $(someButton).observe('click', function() { 
     new Ajax.Updater($('ajaxResponseTarget'), someUrl); 
    }); 
</script> 

Благодаря тому, как события DOM работают, то «щелчок» на .someButtonClass будет стрелять также на #ajaxResponseTarget и Prototype делает его мертвым просто определить какой элемент был объектом события. Никакие события не назначаются элементам в пределах#ajaxResponseTarget, поэтому нет возможности заменить его содержимое на сиротские события из целей внутри.

-3

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

+0

Не могли бы вы немного объяснить? Извините, я не уверен, что вы подразумеваете под «закрытием объекта ответа». Вы имеете в виду функцию? – 2008-11-09 16:45:59

+0

http://en.wikipedia.org/wiki/Closure_(computer_science) – 2008-11-09 17:04:51

Смежные вопросы