2008-11-09 14 views
7

Je travaille sur une application Web conçue pour afficher un ensemble de données mises à jour périodiquement avec AJAX. Le scénario général d'utilisation serait qu'un utilisateur le laisserait ouvert toute la journée et y jette un coup d'oeil de temps en temps.Prévention des fuites de mémoire AJAX

Je rencontre un problème où l'empreinte mémoire du navigateur augmente lentement avec le temps. Cela se produit à la fois dans Firefox et IE 7 (bien que pas dans Chrome). Après quelques heures, IE7 peut avoir une empreinte de ~ 200 Mo et FF3 avoir une empreinte de ~ 400 Mo. Après un grand nombre de tests, j'ai constaté que la fuite de mémoire se produit uniquement si les appels AJAX sont en cours de réponse à. Si le serveur ne répond à rien, je peux laisser la page ouverte pendant des heures et l'empreinte ne grandira pas. J'utilise un prototype pour mes appels AJAX. Donc, je suppose qu'il y a un problème avec le rappel onSuccess créant ces fuites de mémoire.

Est-ce que quelqu'un a des conseils sur la prévention des fuites de mémoire avec prototype/AJAX? Ou des méthodes sur la façon de résoudre ce problème?

EDIT: j'ai découvert que le problème résidait dans une bibliothèque graphique js que j'utilise. Peut être vu here.

Répondre

10

La plus grande chose que vous pouvez surveiller est les événements et comment vous les attribuez.

Par exemple, prenez ce scénario (puisque vous n'avez pas fourni un):

<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 va créer une fuite de mémoire, parce que quand #ajaxResponseTarget est mis à jour (en interne, Prototype utilisera innerHTML) éléments avec click les événements seront supprimés du document sans que leurs événements soient supprimés. La deuxième fois que vous cliquez sur someButton, vous disposez de deux fois plus de gestionnaires d'événements et la récupération de place ne peut pas supprimer le premier ensemble.

Une façon d'éviter cela est d'utiliser la délégation de l'événement:

<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 de la façon dont les événements DOM travail, le « clic » sur .someButtonClass se déclenche aussi #ajaxResponseTarget et Prototype, il est mort simple de déterminer quel élément était la cible de l'événement. Aucun événement n'est affecté aux éléments au sein de#ajaxResponseTarget, il est donc impossible de remplacer son contenu par des événements orphelins à partir des cibles qu'il contient.

+0

+1 Bonne information, bien que je ne crée jamais de nouveaux événements après le chargement initial de la page. J'essaie toujours de comprendre ce que je fais qui pourrait causer le problème. –

+1

Si vous ne créez aucun événement ... pourquoi l'avez-vous accepté comme réponse? – Sean

-3

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

+0

Pourriez-vous expliquer un petit peu? Désolé je ne suis pas sûr de ce que vous entendez par "fermetures autour de l'objet de réponse". Voulez-vous dire une fonction? –

+0

http://en.wikipedia.org/wiki/Closure_(computer_science) –