Logo JavaScript

Création merdique de DOM en JS, plus d’excuses

Flattr this!

Je vais vous parler d'une chose que je vois régulièrement et qui a le don de m'énerver. Je ne dis pas que je ne l'ai jamais fait, mais il ne faut surtout pas le faire, car c'est mal. Oui, je parle de créer des éléments DOM par des concaténations de chaînes de caractères.

Qui, sincèrement, n'a jamais été tenté d'écrire ce genre de code ?

var monLien = "<a href=\"" + lien + "\" title=\"" + description + "\">" + titre + "</a>";

Voyons ensemble les raisons pour lesquelles il ne faut pas faire ça. En introduction, je vous mets le code qu'il aurait fallu écrire pour que ce soit "propre".

var monLien = document.createElement("a");
monLien.href = lien;
monLien.title = description;
monLien.textContent = titre;

1/ Maintenabilité

C'est bête mais il est bien plus difficile de déboguer une chaîne qu'une série d'instructions. Dans le premier cas vous savez que ça plante mais où? Quel est le réel générateur de la panne?

Chaque variable introduite dans votre élément DOM via le second exemple est géré par JS, vous n'avez que l'affectation à faire. Souple et pas moins efficace. Et vous savez aisément quelle est l'instruction qui ne fonctionne pas.

2/ Lisibilité

Le code d'exemple est simpliste là. Même si j'ai pas été très cool avec les guillemets. Mais voyons un code quelque peu plus "lourd".

var select = "<select name=\""+name+"\">";
for(var i = 0; i < mesOptions.length; i++) {
    select += "<option value=\""+mesOptions[i]["valeur"]+"\""+(mesOptions[i]["selected"]?" selected":"")+">"+mesOptions[i]["label"]+"</option>";
}
select += "</select>";

Et sa version DOM :

var select = document.createElement("select");
select.name = nom;
for(var i = 0; i < mesOptions.length; i++) {
    var option = document.createElement("option");
    option.value = mesOptions[i]["valeur"];
    option.textContent = mesOptions[i]["label"];
    option.selected = mesOptions[i]["selected"];
    select.options.add(option);
    delete option;
}

Franchement, c'est pas plus lisible ça?

3/ Performance

J'ai écrit un JSperf il y a quelques semaines que vous avez été nombreux à exécuter et je vous en remercie. Ce test montre clairement que la création par instructions DOM est bien plus rapide que la création par concaténation. Seule la dernière version de Firefox en beta montre une tendance inverse et encore la différence est tellement minimale qu'elle est tout à fait négligeable comparée à d'autres navigateurs actuels qui ont un facteur 8 parfois (cas de Safari).

4/ Testabilité

Dans le cas de la concaténation, vous ne pouvez vérifier votre élément qu'à la fin de la construction de la chaîne. Soit parce que vous avez tout foutu sur une ligne, soit parce que vous ne souhaitez raisonnablement pas vérifier une balise pas finie.

Avec la création via instructions DOM c'est que dès le début, toute votre balise existe et vous vous pouvez déboguer/tester pas à pas votre élément. Pratique et ultime encore une fois.

Conclusion

Comme vous l'aurez compris la façon classique d'écrire des éléments DOM via concaténation de chaînes n'est en rien une bonne pratique. Arrêtez de le faire, n'encouragez plus cette horreur!

Remerciements

Pour le coup, je tiens à remercier toutes celles e tous ceux qui ont déroulés le test, sans vous, il aurait manqué un point clé à cet article. Je ne peux malheureusement nommer que ceux qui m'ont dit l'avoir fait tourner, ne pouvant nommer des visiteurs anonymes. Donc je remercie : l'équipe technique de ma boite, @foxmask, @Chabbinou, @kogratte, @crash__ et @iron_ass. Désolé pour ceux que j'oublie.

Flattr this!

A propos de Mathieu

Ingénieur développeur web dans la vente par correspondance B2B, adepte de nouvelles technologies et d'innovation. Vous pouvez aussi me retrouver sur Twitter @mathrobin
Cette entrée a été publiée dans JavaScript, avec comme mot(s)-clef(s) , , , . Vous pouvez la mettre en favoris avec ce permalien.
  • Quentin

    Les gens qui ont déjà besoin de jQuery pour d’autres raisons aiment bien profiter du chaînage d’instructions proposé :

    var monlien = $("a").attr("href", url).attr("title", description).text(titre);

    C’est facile à découper si besoin, et ça permet de s’abstraire des différences de certains attributs qui, selon la doc jQuery, ne sont pas toujours identiques selon les navigateurs.

    • http://www.mathieurobin.com/ Mathieu

      Exact. Et l’un n’empêche pas l’autre. Il est tout à fait possible de faire ça :

      var monlien = document.createElement("a"),
      $monLien = $(monLien).attr("href", url).attr("title", description).text(titre);

      D’ailleurs tu fais bien de soulever le point de la compatibilité puisqu’ici innerText fonctionne sous Chrome mais pas Firefox. Je sais qu’il y avait un truc pour que ça marche sur les deux mais je ne retrouve plus l’astuce. L’idée était de toute façon de d’abord mettre en avant le fait que la concaténation de chaînes est une erreur à ne pas commettre.

      • http://www.mathieurobin.com/ Mathieu

        En fait, ce n’est pas innerText qui marche sous IE et Chrome, ni text sous FF mais textContent qui marche partout qu’il faut utiliser. J’ai corrigé l’article.

    • http://chez-syl.fr Syl

      Je préfère personnellement plus cette syntaxe :
      var monlien = $('<a>', {
      href: url,
      title: description,
      text: titre
      });​

      • http://chez-syl.fr Syl

        Bon il a exécuté le <a> que j’avais mis. >.<

        • http://www.mathieurobin.com/ Mathieu

          Corrigé 😉

      • http://www.mathieurobin.com/ Mathieu

        Pourquoi pas aussi, c’est vrai qu’autant faire ça si tu as jQuery. Mais seulement si tu disposes de jQuery

      • Quentin

        Oui c’est mieux pour plusieurs attributs. Merci !

  • https://plus.google.com/103518350725594345576/posts Rémi JANOT

    Hello,
    Merci pour ce post bien sympa !
    Quid de l’utilisation de templates en JS ? Tu conseillerais quelle lib ? sans forcément aller jusqu’au MVC.

    • http://www.mathieurobin.com/ Mathieu

      Évidemment, je préfère encore les templates. Il y a du choix. Mustache est sympa mais étant à fond sur EmberJS en ce moment, je préfère Handlebars.

  • http://doanduyhai.wordpress.com Duyhai

    Autre solution, du jQuery templating: http://doanduyhai.wordpress.com/2012/05/10/html-templating-with-jquery/
    (bon, là je fais un peu de la pub pour mon article ^-^)

    Sinon j’aime bien aussi Mustache, par contre quand il faut avoir un peu de logic (if/else) on est coincé …

  • Waateur

    Hey J’avoue que c’est bien plus lisible ! Mais en essayant de l’appliquer je me suis retrouver face a un soucis comment je peut ajouter en gardant la lisibilité d’un document.createElements() pour ajouter ça :

    je suis un texte libre


    Mon exemple est pas super mais l’idée c’est de générer plusieurs éléments imbriqués. ça rend tout de suite les chose complexe non ?

    • Waateur

      Je crois que me suis fait avoir moi aussi :/

    • http://www.mathieurobin.com/ Mathieu

      Tu n’es pas censé (je dis bien censé) avoir un élément qui se promène. C’est la qu’est le problème en réalité. Bon ceci dit, je le fais tout le temps aussi quand c’est moi qui me coltine l’intégration.

      • Waateur

        en faite j’avais une hiérarchie de Div > span > p mais tout à était filtré :/ c’était pour les balises imbriqué mon problème ^^

        • http://www.mathieurobin.com/ Mathieu

          Ah d’accord, là, je ne peux pas corriger vu que je ne vois pas non plus tes balises originelles, ce qui est quelque peu gênant.

          Quasiment toutes les balises ont une propriété qui permet de gérer ses enfants et quand ce n’est pas le cas, c’est qu’il ne peut y avoir d’enfants (genre BR). A partir de là et comme dit dans les commentaires précédents, si tu te retrouves dans la situation où tu dois générer beaucoup de HTML en JS, aucune des deux options dont je parle dans l’article n’est valable. Dans ce cas et dans la grande majorité, il vaut mieux préférer du templating. Comme dans tous langages, il vaut mieux éviter de les mélanger. Le CSS en CSS, le JS avec que du JS et le HTML à sa place dans son coin. Et les moteurs de templates JS ne manquent pas 😉

Articles liés