Articles

bitsofcode

J’ai récemment écrit sur ce que sont exactement le DOM et le DOM virtuel et comment ils diffèrent. Pour récapituler, le Document Object Model est une représentation basée sur des objets d’un document HTML et une interface pour manipuler cet objet. Le shadow DOM peut être considéré comme une version « allégée » du DOM. Il s’agit également d’une représentation d’éléments HTML basée sur des objets, mais pas d’un document autonome complet. Au lieu de cela, le shadow DOM nous permet de séparer notre DOM en petits bits encapsulés qui peuvent être utilisés à travers les documents HTML.

Un autre terme similaire que vous avez peut-être rencontré est le « DOM virtuel ». Bien que le concept existe depuis plusieurs années, il a été rendu plus populaire par son utilisation dans le framework React. Dans cet article, je vais couvrir exactement ce qu’est le DOM virtuel, comment il diffère du DOM original, et comment il est utilisé.

Pourquoi avons-nous besoin d’un DOM virtuel ?

Pour comprendre pourquoi le concept du DOM virtuel a surgi, revisitons le DOM original. Comme je l’ai mentionné, il y a deux parties au DOM – la représentation basée sur l’objet du document HTML et l’API pour manipuler cet objet.

Par exemple, prenons ce simple document HTML avec une liste non ordonnée et un élément de liste.

<!doctype html><html lang="en"> <head></head> <body> <ul class="list"> <li class="list__item">List item</li> </ul> </body></html>

Ce document peut être représenté comme l’arbre DOM suivant :

  • html
    • head lang= »en »
    • body
      • ul class= »list »
        • li class= »list__item »
            .

          • « List item »
          • .

Disons que nous voulons modifier le contenu du premier élément de liste en "List item one" et également ajouter un deuxième élément de liste. Pour ce faire, nous devrons utiliser les API DOM pour trouver les éléments que nous voulons mettre à jour, créer les nouveaux éléments, ajouter des attributs et du contenu, puis finalement mettre à jour les éléments DOM eux-mêmes.

const listItemOne = document.getElementsByClassName("list__item");listItemOne.textContent = "List item one";const list = document.getElementsByClassName("list");const listItemTwo = document.createElement("li");listItemTwo.classList.add("list__item");listItemTwo.textContent = "List item two";list.appendChild(listItemTwo);

Le DOM n’était pas fait pour ça…

Lorsque la première spécification pour le DOM a été publiée en 1998, nous construisions et gérions les pages web de manière très différente. Il y avait beaucoup moins de dépendance sur les API DOM pour créer et mettre à jour le contenu de la page aussi fréquemment que nous le faisons aujourd’hui.

Des méthodes simples telles que document.getElementsByClassName() sont bien à utiliser à petite échelle, mais si nous mettons à jour de multiples éléments sur une page toutes les quelques secondes, il peut commencer à devenir vraiment coûteux d’interroger et de mettre à jour constamment le DOM.

En outre, en raison de la façon dont les API sont configurées, il est généralement plus simple d’effectuer des opérations plus coûteuses où nous mettons à jour de plus grandes parties du document que de trouver et mettre à jour les éléments spécifiques. Pour revenir à notre exemple de liste, il est d’une certaine manière plus facile de remplacer toute la liste non ordonnée par une nouvelle que de modifier les éléments spécifiques.

const list = document.getElementsByClassName("list");list.innerHTML = `<li class="list__item">List item one</li><li class="list__item">List item two</li>`;

Dans cet exemple particulier, la différence de performance entre les méthodes est probablement insignifiante. Cependant, à mesure que la taille de la page web augmente, il devient plus important de ne sélectionner et de ne mettre à jour que ce qui est nécessaire.

… mais le DOM virtuel était!

Le DOM virtuel a été créé pour résoudre ces problèmes de nécessité de mettre à jour fréquemment le DOM d’une manière plus performante. Contrairement au DOM ou au shadow DOM, le DOM virtuel n’est pas une spécification officielle, mais plutôt une nouvelle méthode d’interfaçage avec le DOM.

Un DOM virtuel peut être considéré comme une copie du DOM original. Cette copie peut être fréquemment manipulée et mise à jour, sans utiliser les API du DOM. Une fois que toutes les mises à jour ont été faites sur le DOM virtuel, nous pouvons regarder quels changements spécifiques doivent être faits sur le DOM original et les faire d’une manière ciblée et optimisée.

À quoi ressemble un DOM virtuel ?

Le nom « DOM virtuel » tend à ajouter au mystère de ce que le concept est réellement. En fait, un DOM virtuel est juste un objet Javascript ordinaire.

Revisitons l’arbre DOM que nous avons créé précédemment :

  • html
    • head lang= »en »
    • body
      • ul class= »list »
        • li class= »list__item »
          • « Élément de liste »

    Cette arborescence peut également être représentée comme un objet Javascript.

    const vdom = { tagName: "html", children: } // end ul ] } // end body ]} // end html

    Nous pouvons considérer cet objet comme notre DOM virtuel. Comme le DOM original, il s’agit d’une représentation par objet de notre document HTML. Mais comme c’est un objet Javascript ordinaire, nous pouvons le manipuler librement et fréquemment sans toucher au DOM réel jusqu’à ce que nous en ayons besoin.

    Au lieu d’utiliser un objet pour l’ensemble de l’objet, il est plus courant de travailler avec de petites sections du DOM virtuel. Par exemple, nous pouvons travailler sur un composant list, qui correspondrait à notre élément de liste non ordonnée.

    const list = { tagName: "ul", attributes: { "class": "list" }, children: };

    Sous le capot du DOM virtuel

    Maintenant que nous avons vu à quoi ressemble un DOM virtuel, comment fonctionne-t-il pour résoudre les problèmes de performance et d’utilisabilité du DOM ?

    Comme je l’ai mentionné, nous pouvons utiliser le DOM virtuel pour isoler les changements spécifiques qui doivent être faits au DOM et faire ces mises à jour spécifiques seules. Revenons à notre exemple de liste non ordonnée et faisons les mêmes changements que nous avons fait en utilisant l’API DOM.

    La première chose que nous ferions est de faire une copie du DOM virtuel, contenant les changements que nous voulons faire. Puisque nous n’avons pas besoin d’utiliser les API DOM, nous pouvons en fait juste créer un nouvel objet tout à fait.

    const copy = { tagName: "ul", attributes: { "class": "list" }, children: };

    Ce copy est utilisé pour créer ce qu’on appelle un « diff » entre le DOM virtuel original, dans ce cas le list, et celui mis à jour. Un diff pourrait ressembler à quelque chose comme ceci:

    const diffs = 

    Ce diff fournit des instructions sur la façon de mettre à jour le DOM réel. Une fois que tous les diffs sont collectés, nous pouvons faire des changements par lots au DOM, en faisant seulement les mises à jour qui sont nécessaires.

    Par exemple, nous pourrions boucler à travers chaque diff et soit ajouter un nouvel enfant ou mettre à jour un ancien en fonction de ce que le diff spécifie.

    const domElement = document.getElementsByClassName("list");diffs.forEach((diff) => { const newElement = document.createElement(diff.newNode.tagName); /* Add attributes ... */ if (diff.oldNode) { // If there is an old version, replace it with the new version domElement.replaceChild(diff.newNode, diff.index); } else { // If no old version exists, create a new node domElement.appendChild(diff.newNode); }})

    Notez que c’est une version vraiment simplifiée et dépouillée de la façon dont un DOM virtuel pourrait fonctionner et il y a beaucoup de cas que je n’ai pas couverts ici.

    Le DOM virtuel et les frameworks

    Il est plus courant de travailler avec le DOM virtuel via un framework, plutôt que de l’interfacer directement comme je l’ai montré dans l’exemple ci-dessus.

    Des frameworks tels que React et Vue utilisent le concept de DOM virtuel pour effectuer des mises à jour plus performantes du DOM. Par exemple, notre composant list peut être écrit dans React de la manière suivante.

    import React from 'react';import ReactDOM from 'react-dom';const list = React.createElement("ul", { className: "list" }, React.createElement("li", { className: "list__item" }, "List item"));ReactDOM.render(list, document.body);

    Si nous voulions mettre à jour notre liste, nous pourrions simplement réécrire le modèle de liste entier, et appeler ReactDOM.render() à nouveau, en passant dans la nouvelle liste.

    const newList = React.createElement("ul", { className: "list" }, React.createElement("li", { className: "list__item" }, "List item one"), React.createElement("li", { className: "list__item" }, "List item two"););setTimeout(() => ReactDOM.render(newList, document.body), 5000);

    Parce que React utilise le DOM virtuel, même si nous rendons à nouveau le modèle entier, seules les parties qui changent réellement sont mises à jour. Si nous regardons nos outils de développement lorsque le changement se produit, nous verrons les éléments spécifiques et les parties spécifiques des éléments qui changent.

    Le DOM vs le DOM virtuel

    Pour récapituler, le DOM virtuel est un outil qui nous permet de nous interfacer avec les éléments du DOM d’une manière plus facile et plus performante. Il s’agit d’une représentation objet Javascript du DOM, que nous pouvons modifier aussi souvent que nécessaire. Les modifications apportées à cet objet sont ensuite rassemblées, et les modifications du DOM réel sont ciblées et effectuées moins souvent.