8 votes

Prévenir les fuites de mémoire en AJAX

Je travaille sur une application web qui est conçue pour afficher un ensemble de données qui sont mises à jour périodiquement avec AJAX. Le scénario d'utilisation général serait qu'un utilisateur laisse l'application ouverte toute la journée et y jette un coup d'œil de temps en temps.

Je rencontre un problème où l'empreinte mémoire des navigateurs augmente lentement au fil du temps. Cela se produit à la fois dans Firefox et IE 7 (mais pas dans Chrome). Après quelques heures, l'empreinte mémoire d'IE7 peut atteindre ~200MB et celle de FF3 ~400MB.

Après de nombreux tests, j'ai découvert que la fuite de mémoire ne se produit que si les appels AJAX sont pris en compte. Si le serveur ne répond à rien, je peux laisser la page ouverte pendant des heures et l'empreinte n'augmentera pas.

J'utilise un prototype pour mes appels AJAX. Je suppose donc qu'il y a un problème avec le callback onSuccess qui crée ces fuites de mémoire.

Quelqu'un a-t-il des conseils pour éviter les fuites de mémoire avec les prototypes / AJAX ? Ou des méthodes pour résoudre ce problème ?

EDIT : j'ai découvert que le problème vient d'une bibliothèque graphique js que j'utilise. On peut voir aquí .

11voto

eyelidlessness Points 28034

La principale chose à laquelle vous devez faire attention, ce sont les événements et la manière dont vous les attribuez.

Prenons par exemple le scénario suivant (puisque vous n'en avez pas fourni) :

<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>

Cela créera une fuite de mémoire, car lorsque #ajaxResponseTarget est mis à jour (en interne, Prototype utilisera la fonction innerHTML ) avec des éléments click seront supprimés du document sans que leurs événements ne soient supprimés. La deuxième fois que vous cliquez sur someButton Vous aurez alors deux fois plus de gestionnaires d'événements, et le ramassage des ordures ne pourra pas supprimer le premier ensemble.

Un moyen d'éviter cela est d'utiliser la délégation d'événements :

<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>

En raison du mode de fonctionnement des événements DOM, le "clic" sur la touche .someButtonClass tirera également sur #ajaxResponseTarget et Prototype permet de déterminer très facilement quel élément était la cible de l'événement. Aucun événement n'est attribué aux éléments à l'intérieur #ajaxResponseTarget Il n'est donc pas possible de remplacer son contenu par des événements orphelins de cibles à l'intérieur.

-2voto

Mr. Muskrat Points 2352

Je peux me tromper, mais il semble que vous créez des fermetures autour de l'objet de la réponse. Chaque objet de réponse sera différent, ce qui augmentera l'empreinte mémoire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X