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 :

Utilisation de innerHTML


Sujet :

JavaScript

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre chevronné
    Homme Profil pro
    Analyse système
    Inscrit en
    Mai 2014
    Messages
    392
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Arménie

    Informations professionnelles :
    Activité : Analyse système
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2014
    Messages : 392
    Par défaut Utilisation de innerHTML
    Bonjour,

    Dans la discussion :
    https://www.developpez.net/forums/d1...ipt-page-html/

    Je proposais d'utiliser innerHTML pour ajouter du code à une page html. Pour moi, c'est une solution parmi d'autres.
    • NoSmoking trouvait que "ce pas un cadeaux à faire à un débutant...".
    • Watilin trouvait que "sous tout point de vue, il est la pire des solutions...".

    Concrètement quels problèmes, quelles difficultés pose cette solution? Si je veux supprimer ce qui est contenu entre deux balises, y a-t-il un inconvénient à écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    document.getElementById("identifiant").innerHTML="";

  2. #2
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    17 198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 17 198
    Par défaut
    Bonjour,
    Concrètement quels problèmes, quelles difficultés pose cette solution? Si je veux supprimer ce qui est contenu entre deux balises, y a-t-il un inconvénient à écrire :
    Cette façon de faire outre le fait qu'elle soit bien moins rapide qu'un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    while (elem.firstChild) {
       elem.removeChild(elem.firstChild);
    }
    présente l’inconvénient de boguer, dans certaines conditions, sous IE, mais bon certains diront ..., Bovino avait fait une réponse en ce sens, voir la discussion : https://www.developpez.net/forums/d9...l/#post5463783.

    Il en ressort que l'utilisation de removeChild est tout à fait satisfaisante.
    On a Bug IE
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    function ajout(){
      var oDiv = document.getElementById('test');
      oDiv.innerHTML = k++;
      oDiv.appendChild(div1);
    }
    contre OK IE (plus verbeux mais terriblement efficace !)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    function ajout(){
      var oDiv = document.getElementById('test');
      while (oDiv.firstChild) {
        oDiv.removeChild(oDiv.firstChild);
      }
      oDiv.innerHTML = k++;
      oDiv.appendChild(div1);
    }
    Ceci concernait le « vidage » d'éléments.


    Concernant l'« emplissage » d'éléments l'utilisation de innerHTML est également bien souvent moins rapide que les méthodes utilisant l'API DOM, ceci étant principalement du au « parsage » de la chaine fournie à innerHTML.

    Comment fonctionnent les navigateurs.

    Je rajoutes le lien fourni récemment dans une discussion par Watilin : element.innerHTML.

    Voilà pour un début de réflexion

  3. #3
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    je ne suis pas un "expert" en JS, mais...

    1- Pour SUPPRIMER le contenu d'un élément (<div>) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    document.getElementById("identifiant").innerHTML="";
    Me semble bien.
    Même si :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    document.getElementById("identifiant").textContent="";
    semble suffisant.

    2- Pour AJOUTER du contenu (à celui existant) :

    Cela dit, perso, je continue à utiliser .innerHTML() ou textContent()...
    Tout dépend de ce qu'on veut faire...

    Les experts en JS trancheront.
    Dernière modification par NoSmoking ; 04/03/2019 à 17h21.

  4. #4
    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
    eleydet, tu poses une très bonne question

    innerHTML a essentiellement 4 problèmes.

    1. L’ambigüité : rien ne nous empêche de passer du code HTML mal construit. Le navigateur compense alors comme il peut, ce qui introduit potentiellement des erreurs difficiles à détecter. De plus, les mécanismes de correction de code HTML ne sont pas standardisés, et peuvent varier selon les navigateurs.

    2. La sécurité : c’est le point expliqué dans l’article MDN que NoSmoking et moi-même avons lié, je ne reviens pas dessus.

    3. La corruption du DOM. Ce problème est plus subtil et moins connu. Ça se produit quand on écrit .innerHTML +=. Un exemple :
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    <div id="exemple">
      <button>Cliquez là</button>
    </div>

    Code JS : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    let divExemple = document.getElementById("exemple");
    divExemple.querySelector("button").addEventListener("click", function () {
      alert("Vous avez cliqué sur le bouton");
    });

    Supposons que je veuille ajouter une balise dans la div #exemple en utilisant innerHTML :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    divExemple.innerHTML += "<p>Du texte en plus</p>";
    Cette instruction se décompose comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    let html = divExemple.innerHTML;
    html = html + "<p>Du texte en plus</p>";
    divExemple.innerHTML = html;
    Le contenu entier de la div va être recréé. L’ancien <button> est supprimé, et un nouveau est recréé à partir de sa représentation HTML textuelle. Ce n’est plus le même élément DOM, et les références sont brisées, en particulier les gestionnaires d’évènements qui y étaient attachés. Dans mon exemple, le gestionnaire de "click" ne fonctionnera plus.

    4. La performance : passer une chaîne HTML sera toujours moins performant qu’utiliser les méthodes du DOM (createElement, append*, insert*), car le moteur JS est obligé de faire appel à l’analyseur HTML du navigateur.
    Bien qu’il ne faille pas chercher la performance à tout prix, ça reste une chose importante à considérer. On s’épargne de la réécriture de code en fin de projet si on a utilisé le DOM dès le départ.




    Du fait de sa popularité, innerHTML pose encore un cinquième problème : il cause du tort à la communauté JavaScript. Je vais m’expliquer.

    innerHTML est une solution de facilité, car il faut reconnaître que c’est fastidieux de construire un fragment HTML en utilisant uniquement les méthodes du DOM. Après tout, c’est pour ça que les frameworks existent.

    (Petite note : bien que jQuery soit optimisé avec soin, il est aussi parfois obligé de faire appel à innerHTML au lieu des méthodes du DOM. Tout dépend de comment on l’utilise. Comme en JS vanilla, il y a aussi de bonnes et de mauvaises pratiques avec jQuery.)

    Ça irait encore si on n’utilisait innerHTML par flemme, que pour du prototypage et des petits projets. Mais c’est plus insidieux quand ceux et celles qui transmettent le savoir ont la flemme d’expliquer, et conseillent innerHTML aux débutants. Ainsi, la mauvaise pratique se répand.

    En fait, ce n’est pas beaucoup plus compliqué de parler de textContent qui répond souvent au besoin, ou bien de insertAdjacentHTML. Ce dernier ne résoud pas tous les problèmes, mais il est déjà plus performant, et il ne corromp pas le DOM.




    Par honnêteté, abordons les cas légitimes d’utilisation de innerHTML :

    Pour vider un élément ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    element.innerHTML = "";
    Comme l’a écrit NoSmoking, ainsi que l’auteur de ce billet de blog, ce n’est pas performant.

    D’autre part, en regardant le code de jQuery, on trouve ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    empty: function() {
      var elem,
        i = 0;
     
      for ( ; ( elem = this[ i ] ) != null; i++ ) {
        if ( elem.nodeType === 1 ) {
     
          // Prevent memory leaks
          jQuery.cleanData( getAll( elem, false ) );
     
          // Remove any remaining nodes
          elem.textContent = "";
        }
      }
     
      return this;
    },
    A priori, les devs de jQuery ont jugé que elem.textContent = "" était le plus efficace. Je leur fais confiance.

    pour sérialiser un fragment de document, et le sauvegarder, par exemple dans le localStorage, ou encore l’envoyer vers le serveur.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    let serializedHtml = element.innerHTML;
    On l’utilise alors en lecture, et uniquement en lecture ! Si on a besoin de ré-injecter le code plus tard, on utilisera alors insertAdjacentHTML.
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  5. #5
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 910
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 910
    Par défaut
    Salut,

    Je m'étais déjà interrogé ici : La fonction unwrap() en JS pur ?, je me disais que la deuxième solution (avec innerHTML et outerHTML) était peut-être plus rapide mais d’après ce que je lis dans ce présent fil ce ne serait peut-être pas le cas ???

    ---> Sinon je me pose une question : dans tous les cas n'y a-t-il pas un problème de libération mémoire dans certains cas ? Je veux dire que si on supprime un élément du DOM est-ce que la mémoire qu'il occupe est libérée ? Je pose la question car j'ai cru comprendre que pour que la mémoire soit libérée il fallait aussi supprimer les éventuels gestionnaires d’événement attachés à cet élément du DOM, non ???

  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
    Citation Envoyé par Beginner. Voir le message
    ---> Sinon je me pose une question : dans tous les cas n'y a-t-il pas un problème de libération mémoire dans certains cas ? Je veux dire que si on supprime un élément du DOM est-ce que la mémoire qu'il occupe est libérée ? Je pose la question car j'ai cru comprendre que pour que la mémoire soit libérée il fallait aussi supprimer les éventuels gestionnaires d’événement attachés à cet élément du DOM, non ???
    C’est un problème pour le ramasse-miettes. Avec d’anciennes versions d’IE il y avait des fuites, mais aujourd’hui, en principe (je dis bien en principe ) il n’y a plus ce genre de souci.
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  7. #7
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 910
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 910
    Par défaut
    Merci.

    Alors c'est vrai que par exemple dans cet article Memory leaks and memory management in JavaScript il mentionne le problème de IE mais après j'ai l'impression que les autres problèmes qui sont évoqués concernent aussi les navigateurs modernes mais j'en suis pas sûr...

    Après dans cet article Avoiding Memory Leaks on peut voir d'autres cas et il y aurait deux ramasse miettes si j'ai bien compris (un pour JS et un pour le DOM), on peut lire notamment ce conseil :
    As always remember to clean up the js objects/events first before removing the dom nodes. Javascript’s Garbage Collector is able to detect circular references and handle them correctly, but the DOM’s Garbage Collector can not.
    Mais c'est vrai que ces articles ont quelques années déjà et si ce n'est plus un problème alors tant mieux...

    ----

    Dans le code source que tu as posté on a entre autres :

    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    // Prevent memory leaks
    jQuery.cleanData( getAll( elem, false ) );

    Est-ce mis pour IE ou bien c'est valable aussi pour les autres navigateurs ?

  8. #8
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    17 198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 17 198
    Par défaut
    3. La corruption du DOM.
    (...)
    Tout à fait pertinent de le rappeler


    Bien qu’il ne faille pas chercher la performance à tout prix, ça reste une chose importante à considérer.
    Je suis d'accord avec le fait que la performance n'est pas tout mais qu'elle est un bon indicateur de comment travail le navigateur, on peut supposer que plus c'est rapide et moins le moteur JavaScript « patine ».

    En utilisant la méthode removeChild il suffit dans la représentation de l'arbre du DOM de rompre la relation du noeud avec le parent, dans le cas de innerHTML="" on sera de toute manière obliger de « parser » la chaine pour pouvoir rompre également ces relations.
    Comme expliqué par Watilin le ramasse-miettes fera le ménage en cas de non référence pointant sur le noeud libéré.


    A priori, les devs de jQuery ont jugé que elem.textContent = "" était le plus efficace. Je leur fais confiance.
    A partir du lien de performance fourni je suis tombé sur cette analyse : https://jsperf.com/innerhtml-vs-removechild/469, celle-ci met au même niveau textContent="" et innerHTML="" ce qui me paraît logique.

    Je pense donc que les dev jQuery ont plutôt fait dans le concis, même si visuellement innerHTML="" me paraît plus parlant sur l'action effectuée que textContent="".

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

Discussions similaires

  1. Utilisation de .innerHTML
    Par Invité dans le forum Général JavaScript
    Réponses: 7
    Dernier message: 26/06/2012, 11h04
  2. focus incorrect sur chrome lors de l'utilisation de innerHTML
    Par visqueu dans le forum Général JavaScript
    Réponses: 7
    Dernier message: 24/01/2012, 17h29
  3. Bonne utilisation de innerHTML
    Par glove dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 29/04/2009, 14h40
  4. Utilisation de innerHTML
    Par E.Bzz dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 26/01/2007, 09h54
  5. [javascript] utilisation de innerHTML
    Par TERRIBLE dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 18/11/2005, 09h26

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