Cette dernière partie de la spécification des web components est sûrement celle qui va avoir le plus d'impact sur les performances de nos applications, contrairement aux templates, shadow dom et éléments customs qui sont certainement plus orientés pour améliorer la productivité des développeurs. Nous allons donc voir comment "observer notre application", observer le DOM ainsi que le modèle.

On fait comment de nos jours ?

Aujourd'hui, pour observer les changements du DOM, nous utilisons les MutationEvent. Par exemple, pour être notifié de l'ajout d'un élément au DOM, on ajoute un listener sur le document

document.addEventListener('DOMNodeInserted', function(e) {
  console.log(e.target);
}, false);

Cette façon de faire n'est pas performante. D'une part à cause de la propagation des évènements et de la nature asynchrone de cette méthode. Ensuite car ces évènements sont envoyés beaucoup trop souvent, à chaque changement, sans possibilité de les grouper.

Demain, avec les Web Components...

Demain, ce sera mieux, évidemment !

La spécification Web Components nous apporte les Mutation Observers qui vont nous permettre d'observer les changements du DOM, sans avoir recours à la programmation événementiel. Concrètement, qu'est-ce que ça change ?

Les Mutations Observers ne sont notifiés qu'à la fin des modifications du DOM, lorsqu'il y en a plusieurs simultanément par exemple. Ce qui implique que ce que l'on va recevoir une liste de changements et non plus un seul.

On crée tout d'abord l'observer, avec la fonction qui va être notifiée des changements et effectuera les actions voulues.

var observer = new MutationObserver(function(mutations, observer) {
  mutations.forEach(function(record) {
    for (var i = 0, node; node = record.addedNodes[i]; i++) {
      console.log(node);
    }
  });
});

Sur cet objet, on va ensuite appeler la méthode observe

observer.observe(el, {
  childList: true,      // Être notifié des ajouts/suppressions de noeud
  subtree: true,        // Observer également le subtree
  characterData: true,  // Inclure les changements de contenu
  attribute: true       // Inclure les changements d'attribut dans le subtree
});

Enfin, on peut choisir d'arrêter l'observation

observer.disconnect();

Observer les changements du modèle

On peut observer les changements du DOM assez simplement et efficacement... pas mal ! Mais ce que je trouve encore plus sympathique, c'est la possibilité d'observer les changements sur des objets JavaScript.

Tout comme pour l'observation du DOM, une fonction va être notifiée des changements sur un objet. Pour chaque changement, plusieurs informations vont être disponibles

function observeChanges(changes) {
  console.log('== Callback ==');
  changes.forEach(function(change) {
    console.log('Ce qui a changé', change.name);
    console.log('La nature du changement', change.type);
    console.log('L''ancienne valeur', change.oldValue );
    console.log('La nouvelle valeur', change.object[change.name]);
  });
}

Enfin, démarrer l'observation.

var o = {};
Object.observe(o, observeChanges);

Tout ça pour ça ?

Concrètement, tous les développeurs ne vont pas avoir besoin des Observers. Cette fonctionnalité vise principalement les auteurs de framework, les développeurs d'extensions... Avec (si vous avez suivi) en ligne de mire le databinding et les MDV, Model-Driven-View

Voici un graphe que j'ai honteusement piqué sur la présentation d'Eric Bidelman (Si je retrouve la source originale, je la mettrai ici), montrant les performances constatés par l'équipe d'AngularJS avec dans un cas le databinding fait de façon "classique" et dans un deuxième cas, en utilisant les Observers (Disponibles sur un branche de dev de Chromium)

The end

Il s'agissait du dernier article de la série. J'espère avoir réussi à vous inciter à suivre de près cette spécification, qui est selon moi un grand pas en avant dans le monde du Web, comme peut l'être HTML5 aujourd'hui.

Disclaimer : Tout ce que j'ai pu écrire dans ces articles ne sera peut-être plus vrai au moment où vous les lirez. La spécification est encore à l'état draft et donc susceptible de changer avant sa sortie officielle.

Les autres articles de la série sur les WebComponents :