IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaScript Discussion :

Un événement écoute-t-il toujours lorsque l'élément visé est supprimé du DOM ?


Sujet :

JavaScript

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2013
    Messages
    150
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2013
    Messages : 150
    Par défaut Un événement écoute-t-il toujours lorsque l'élément visé est supprimé du DOM ?
    Bonsoir,

    Lorsque je créer un événement sur un élément du DOM et que par la suite cette élément vient à être supprimer du DOM l’événement écoute il encore cette élément qui à été supprimé ou le supprime t-il automatiquement ?

    Autrement dit, lorsque je supprime un élément qui est écouter par un événement dois-je au préalable supprimer l’événement ?

  2. #2
    Expert confirmé
    Avatar de sekaijin
    Homme Profil pro
    Urbaniste
    Inscrit en
    Juillet 2004
    Messages
    4 205
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Urbaniste
    Secteur : Santé

    Informations forums :
    Inscription : Juillet 2004
    Messages : 4 205
    Par défaut
    Un événement est un objet éphémère. Il n'existe qu'à l'instant où il se produit et disparait lors que tous les handlers qui lui sont associés ont été exécutés.

    si tu associes une fonction aux événements mouseOver d'un DIV.
    l'événement mouseOver est créé lorsque la souris entre dans la zone du DIV.
    Il est détruit lorsque la dernière fonction qui lui est associée a fini de s'exécuter.

    Lorsque tu détruis le DIV, l'événement n'existe pas. Il ne peut pas être détruit.

    De même sur un bouton si tu fournis une fonction associée au click et que tu détruis le bouton.
    Tant que tu n'as pas cliqué sur le bouton il n'y a pas d'événement click et lorsque la fonction a fini il n'y en a plus.

    Dans la vie d'un homme (ou une femme), il y a un certain nombre d'événements qui peuvent survenir.
    Par exemple le mariage.
    Tu peux prévoir de chanter un petit truc pour le mariage de ton ami.
    Mais tant qu'il ne se marie pas, l'événement «mariage de ton ami» n'existe pas.
    Il n'existera, peut-être jamais, ou peut-être en existera-t-il plusieurs.
    Cela ne t'a pas empêché de prévoir de chanter un petit truc pour son mariage.

    La définition de «événement» dans mon dico est :
    Ce qui se produit; circonstance, situation.

    il en va de même en informatique
    Un événement est ce qui se produit.

    Je ne sais donc pas trop ce que tu cherches.
    Pour comprendre ce qu'il se passe lorsque tu détruis un objet il faut comprendre la notion de référence.
    Tu crées deux variables qui représentent chacun un objet. Et tu affectes à un membre du premier objet le second.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    var var1 = {};
    var var2 = {};
    var1.obj2 = var2D
    ans ce simple code, tu crées dans la mémoire 5 choses.
    la variable var1 qui est une référence (une @dresse en mémoire)
    la variable var2 qui est une référence (une @dresse en mémoire)
    un objet dont l'@dresse en mémoire est référencé par var1
    un autre objet dont l'@dresse en mémoire est référencé par var2

    var1 n'est pas un objet, mais une référence à un objet.
    var2 n'est pas un objet, mais une référence à un autre objet.

    Et, enfin obj2 est une référence créée dans l'objet et a pour valeur l'@dresse de l'autre objet.

    Maintenant, tu affectes null à var 2Var2 ne référence plus l'autre objet. Pour autant l'autre objet existe toujours. En effet tu peux toujours obtenir sa référence au travers de var1.obj2.
    L’autre objet ne sera détruit que lorsque toutes les références ayant pour valeur son @dresse seront détruites.

    Maintenant, appliquons cela à ton problème d'événement.
    tu définis une fonction toto
    tu crées un DOMElement
    Tu associes la fonction toto avec le type d'événement mouseOver du DOMElement.

    Que se passe-t-il dans cette séquence*?
    tu crées un objet de type fonction
    tu crées une référence «toto» qui contient l'@dresse de cette fonction
    tu crées un DOMElement
    Et tu affectes une référence à la fonction au membre 'onmouseover' du DOMElement.

    Notes qu'à aucun moment un événement n'a été créé. Pour cela il faudrait que la souris survole le DOMElement.

    Si tu détruis le DOMElement tous ses membres sont détruits onmouseover aussi.
    La question est : la fonction est-elle détruite ?
    La réponse se trouve dans les références. Comme tout objet elle n'est détruite que si toutes les références le sont. «toto» est une référence qui existe toujours ; la fonction existe donc.

    Notes encore qu'il n'est nullement question de l'événement.

    En détruisant le DOMElement tu détruis l'objet en mémoire et toutes les références qu'il contient.
    Mais tu ne détruis pas obligatoirement les objets référencés.

    Mais tu peux avoir créé ton DOMElement et ta fonction d'une autre façon.
    tu crées un DOMElement
    Tu associes la fonction nouvelle fonction avec le type d'événement mouseOver du DOMElement.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    elem.onmouseover = function(e) {....};
    il n'existe alors qu'une seule référence à la fonction elem.onmouseover
    Si tu détruis l'élément, toutes les références à la fonction auront été détruites, donc la fonction le sera aussi.

    A+JYT

  3. #3
    Expert confirmé
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 094
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 094
    Par défaut Oui
    Bonjour,

    un élément hors du DOM peut avoir un gestionnaire d'évènement, la preuve :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // création d'une div hors du DOM
    var $div = document.createElement('div');
     
    // attachement d'un gestionnaire
    var listener = function(event) {
       console.log(event);
    };
    $div.addEventListener('click', listener);
     
    // émission d'un clic artificiel sur la div
    $div.dispatchEvent(new MouseEvent('click'));
    Lorsque tu exécutes ce code, la console affiche l'évènement clic, alors que la div n'est pas rattachée au DOM.

    Quand tu retires un élément du DOM, la plupart des évènements « naturels » ne peuvent plus l'atteindre (c'est pour ça que j'ai utilisé un clic artificiel dans mon exemple). Mais les gestionnaires d'évènements y sont toujours attachés.

    Si tu cherches à libérer de la mémoire, ne t'en fais pas, le ramasse-miettes de JS est tout à fait capable de récupérer des gestionnaires d'évènements (sauf sous de vieilles versions d'IE). Ainsi, si l'élément que tu retires du DOM n'est pas représenté par une variable gobale, il sera récupéré par le ramasse-miettes quand la variable sera supprimée. Si tu veux vraiment être sûr, tu peux toujours faire maVariable = null;.

    Pour finir, JavaScript n'est pas fait pour la gestion de mémoire comme en C++. Normalement le développeur n'a pas besoin de s'en occuper. Si la méthode removeEventListener existe, c'est pour les cas où on a effectivement besoin qu'un gestionnaire cesse de faire effet sur un élément, sans retirer cet élément du DOM.

    Edit: en même temps Sekai
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  4. #4
    Membre émérite

    Profil pro
    Inscrit en
    Juin 2007
    Messages
    748
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 748
    Par défaut
    moué oué oué...


    prenons l'exemple de A et B étant 2 entités. A et B représentent les éléments DOM ul > li:eq(0) et ul > li:eq(1);

    attachons un event 'click' sur (ul li), donc sur les entités A et B, et bien figurez vous que il n'est pas si anodin de savoir comment détruire l'event sur A sans le détruire sur B, et aussi si il est détruit totalement puisque nous supprimons A et non B.

    le event register si on ne fait pas attention, cible le chemin DOM, donc si on ne différencie pas event:li:eq(0) de event:li:eq(1) impossible de les différencier (sauf dans le calback , normal )

    l'event register cible les elements, sachant cela, il suffis de bien cibler les elements 1 par 1, et / ou de savoir globalement quel event est propagé sur quelles cibles, et la fonction inverse est alors possible, il est alors possible de supprimer un event register sur une cible avant de supprimer la cible

  5. #5
    Expert confirmé
    Avatar de sekaijin
    Homme Profil pro
    Urbaniste
    Inscrit en
    Juillet 2004
    Messages
    4 205
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Urbaniste
    Secteur : Santé

    Informations forums :
    Inscription : Juillet 2004
    Messages : 4 205
    Par défaut
    le event register si on ne fait pas attention, cible le chemin DOM, donc si on ne différencie pas event:li:eq(0) de event:li:eq(1) impossible de les différencier (sauf dans le calback , normal )
    que non
    que non
    pas du tout
    le handler d'événement s'attache à l'élément pas au type d'élément.
    si tu attache un handler sur 'click' pour les élément UL > LI
    en fait tu attache individuellement le handler sur chaque LI.
    si tu détruit un LI les autres ne sont pas affectés.
    cela revient à faire quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var LIs = document.getElementsByTagName('LI');
    // attachement d'un gestionnaire
    var listener = function(event) {
       console.log(event);
    };
    for(var i = 0; i < LIs.length ; i++){
      LIs.item(i).addEventListener('click', listener);
    }
    //suppression du 5eme LI
    LIs.item(5).parentNode.removeChild(LIs.item(5));
     
    LIs.item(3).dispatchEvent(new MouseEvent('click'));
    A+JYT

  6. #6
    Expert confirmé
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 094
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 094
    Par défaut
    Ascito,
    Citation Envoyé par ascito Voir le message
    event:li:eq(0)
    Je ne comprends pas cette notation event:, peux-tu l'expliquer ?
    De plus, le sélecteur :eq() c'est une syntaxe jQuery (ou autre framework). Ici on est sur le forum « JavaScript général » donc évitons de parler de frameworks quand c'est possible.

    Je plussoie les remarques de Sekaijin, et je me demande (ne le prends pas comme un atteinte personnelle) si tu comprends pleinement les mécanismes de gestion d'évènement qui se passent « sous le manteau » quand on a recours à un framework. Plus précisément, quand tu dis :
    attachons un event 'click' sur (ul li), donc sur les entités A et B
    je crois que tu parles en fait de déléguer la gestion du clic sur la <ul>, ce qui se fait de manière transparente avec un framework, mais n'est pas anodin en réalité :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    var $ul = document.querySelector('ul');
     
    $ul.addEventListener('click', function(event) {
       // on examine event.target avant d'agir
       if ('LI' === event.target.tagName) {
          console.log('click sur un <li>');
       } // else ne rien faire
    });
    Ici le clic est intercepté sur tous les éléments descendants de la <ul>, mais seuls ceux qui ont lieu sur les <li> ont un effet visible. Il n'y a qu'un seul gestionnaire d'évènement, donc si on le retire, tous les descendants sont concernés.
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  7. #7
    Rédacteur/Modérateur

    Avatar de SylvainPV
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    3 375
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 3 375
    Par défaut
    Le pauvre Crackerz doit être paumé avec tout ça

    En résumé, ce que tu crées n'est pas l’événement en soi mais l'écouteur d’événements (Event Listener). L'écouteur reçoit en paramètre une fonction, le callback, qui est appelé par l'Event Listener lorsque l’événement survient. Donc ta véritable question est : est-ce que la fonction callback d'un listener d'événement sur un élément HTML est virée de la mémoire quand l'élément HTML est supprimé ?

    Et c'est une très bonne question, car une cause courante de fuite mémoire. En effet, si l'élément n'est pas réellement supprimé (si on le détache du DOM en gardant une référence en JavaScript par exemple avec jQuery.detach()), ni l'élément ni les event listeners et callbacks associés vont être dégagés par le garbage collector. Et tout ça va squatter la RAM. Mais généralement c'est le comportement désiré, parce que détacher un élément du DOM permet de le rattacher à nouveau sans avoir besoin de réinitialiser tous les event listeners.

    Si tu supprimes l'élément "proprement" (removeChild ou modification sur un élément parent), tous les bons navigateurs feront le ménage pour toi. IE6 et IE7 n'en font pas partie, cela va de soi.

  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2013
    Messages
    150
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2013
    Messages : 150
    Par défaut
    Bonjour,

    Merci pour toutes vos réponses, le résumé de fin est tombé à pic ^^

    Je vais prendre le temps de bien faire les choses en étudiant d'un peu plus prés ce qui se passe après une action

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 0
    Dernier message: 02/05/2012, 11h04
  2. Réponses: 6
    Dernier message: 08/09/2011, 11h53
  3. Réponses: 6
    Dernier message: 26/10/2006, 17h01
  4. Ajout de deux colonnes lorsqu'une des deux est à null
    Par KibitO dans le forum Langage SQL
    Réponses: 1
    Dernier message: 12/09/2006, 14h07
  5. Masquer un div lorsque la souris n'est plus dessus
    Par Agoye dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 27/04/2006, 20h50

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo