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

  1. #1
    Community Manager

    [Article] Comprendre le data binding dans Angular, React et Vue
    Chers membres du club,

    Je vous présente ce tutoriel de SylvainPV sur comprendre le data binding dans Angular, React et Vue.


    Les frameworks MVVM sont aujourd'hui une partie centrale du développement front-end d'applications web. Ils occupent souvent l'actualité JavaScript et sont source de grands débats parmi les professionnels.

    Derrière cette appellation, on retrouve un principe de base reliant le Modèle (M) à la Vue (V) : le data binding. Pourtant ce mécanisme est souvent mal connu ou mal compris par les utilisateurs de ces frameworks, perdus dans le jargon technique et marketing.

    Nous allons tâcher de décrire comment ce mécanisme de data binding est implémenté au sein de trois frameworks populaires : Angular, React et Vue.
    Bonne lecture



    Les meilleurs cours et tutoriels pour apprendre la programmation JavaScript
    Les meilleurs cours et tutoriels pour apprendre la programmation Web
    Pour contacter les différents services du club (publications, partenariats, publicité, ...) : Contacts

  2. #2
    Membre éclairé
    Merci SylvainPV pour cet excellent aperçu des différentes solutions en data-binding.

    Je trouve aussi que Vue.js est une solution légère et élégante en matière de data-binding. La question qui, en ce qui me concerne, n'est pas tranchée, est la suivante : le data-binding vaut-il réellement la peine, par rapport à une manipulation plus traditionnelle des éléments du DOM via Sizzle/jQuery ou même les API standards ?

  3. #3
    Rédacteur/Modérateur

    Tout dépend si tu optes pour un rendu des vues côté client ou côté serveur. Si l'essentiel de ton rendu est fait côté serveur, et que les interactions côté client ne sont pas trop complexes, une manipulation directe et manuelle du DOM est sans doute plus simple. En revanche, si le rendu est fait côté client, on a tout intérêt à se reposer sur une solution de data-binding afin que toutes les vues soient conditionnés par le modèle. Cela permet de limiter les états applicatifs et de simplifier énormément la gestion. Tu es déjà sûrement tombé dans le cas où tu as un plugin UI jQuery qui doit modifier le DOM pour s' "initialiser", et sur lequel tu dois toujours te poser la question de s'il est initialisé ou pas, ou "en cours d'initialisation". Ces "états" de vues n'existent plus quand tu pars sur une solution comme React ou vuex.

    Si tu te rappelles de mon article sur le templating client, tu sais que je penche nettement en faveur du rendu côté client, pour la compensation de latence, la réduction de la bande-passante utilisée et l'ouverture à l'usage offline
    One Web to rule them all

  4. #4
    Membre éclairé
    Je parle aussi d'application JavaScript embarquée dans le navigateur. Le data-binding n'est pas un lien entre le modèle et la vue au sens MVC du terme. Il s'agit plutôt d'un moyen d'agir sur la vue au travers d'une représentation. Je veux dire que les modèles des vues ne sont pas le modèle de l'application, et la synchronisation entre les (modèles de) vues et le modèle de l'application est en dehors de la problématique du data-binding.

    On peut programmer de manière modulaire, par "composants", c-à-d en regroupant le code CSS, les templates HTML et le code JS par petites entités fonctionnelles, tout en manipulant directement des éléments du DOM.

  5. #5
    Rédacteur/Modérateur

    Oui, on se rapproche alors davantage d'un pattern MVC que MVVM.
    One Web to rule them all

  6. #6

  7. #7
    Membre éclairé
    L'approche de Monkberry semble saine : pas de data binding, pas de DOM virtuel, aucune magie.

    Un langage de template :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    <div>
      Hello {{ name }}!
    </div>


    … compilé en code JavaScript utilisant les objets DOM standards :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    var div1 = document.createElement('div');
    div1.textContent = 'Hello ' + name + '!';

  8. #8
    Rédacteur/Modérateur

    Intéressant. C'est bien du data-binding, à partir du moment où il y a des mises à jour partielles du DOM et une résolution des liaisons dans un modèle de données. Pour la magie c'est plus subjectif comme définition J'ai joué avec une petite heure, voilà mon analyse :

    Pour la détection de changements, c'est du classique: une API de changement d'état à la React/Backbone. Le templating est DOM-based (on ne peut pas mettre d'expressions pour définir un tag par exemple), mais il y a les moustaches comme sucre syntaxique pour l'interpolation de texte et attributs.

    Concernant la mise à jour du DOM, c'est plus particulier : la compilation du template consiste en fait à le faire passer par un parser HTML qui va écrire le code JS correspondant pour générer ce HTML à partir des API du DOM, avec le bon vieux document.createElement. Ces éléments sont créés un par un et assignés à des références en mémoire. Lorsque des liaisons de données sont détectées pour un élément, chaque donnée aura un setter associé qui fera les modifications sur l'élément en question. C'est un peu comme si vous écriviez vos mises à jour du DOM à la main, sauf que là c'est un compilateur qui s'en charge.

    Un exemple vaut mieux qu'un long discours. Le template:
    Code html :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    <div>
       <p>
          Hello {{ name }}!
       </p>
       <p>Monkberry is <i>almost</i> an anagram of Monkey beer</p>
    </div>


    est compilé en :

    Code js :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
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    /**
     * @class
     */
    function hello() {
      Monkberry.call(this);
     
      // Create elements
      var div0 = document.createElement('div');
      var p1 = document.createElement('p');
      var text2 = document.createTextNode('');
      var p3 = document.createElement('p');
      var i4 = document.createElement('i');
     
      // Construct dom
      p1.appendChild(document.createTextNode(" Hello "));
      p1.appendChild(text2);
      p1.appendChild(document.createTextNode("! "));
      i4.appendChild(document.createTextNode("almost"));
      p3.appendChild(document.createTextNode("Monkberry is "));
      p3.appendChild(i4);
      p3.appendChild(document.createTextNode(" an anagram of Monkey beer"));
      div0.appendChild(p1);
      div0.appendChild(p3);
     
      // Update functions
      this.__update__ = {
        name: function (name) {
          text2.textContent = name;
        }
      };
     
      // Set root nodes
      this.nodes = [div0];
    }
    hello.prototype = Object.create(Monkberry.prototype);
    hello.prototype.constructor = hello;
    hello.pool = [];
    hello.prototype.update = function (__data__) {
      if (__data__.name !== undefined) {
        this.__update__.name(__data__.name);
      }
    };
     
    window.hello = hello;
    //# sourceMappingURL=view.js.map


    Les avantages et les inconvénients apparaissent alors clairement:

    Avantages:
    • les mises à jour du DOM sont effectivement les plus minimales possibles, puisque chaque donnée a son setter dédié
    • le template une fois compilé reste lisible et exploitable en tant que tel


    Inconvénients:
    • une fois compilé, le code est très, très verbeux. Avec cet exemple très simple on a multiplié par 10 la taille du code après compilation. Et plus les liaisons dans le template seront complexes, plus ce facteur risque d'augmenter.
    • il n'y a actuellement pas d'optimisation pour gérer les parties statiques des templates. Le second paragraphe est ainsi construit manuellement avec ses références sans que cela soit vraiment nécessaire.


    Vu que la latence réseau reste le problème de perf numéro 1 pour l'usage web, le fait que la précompilation vienne décupler la taille des templates est un énorme désavantage, que le faible poids de la lib en elle-même peut difficilement compenser à lui seul (et puis afficher le poids gzippé c'est tricher :p ). A la rigueur, je peux y voir un intérêt pour les applications JS hors-ligne ou embarquées. Mais alors le faible poids de la lib n'est plus un argument en sa faveur non plus.

    J'ai aussi de grosses craintes sur la résolution de divers problèmes tels que les boucles infinies ou la résistance aux modifications inopinées du DOM. C'est le genre de chose pour lesquels Angular/React/Vue ont des mécanismes dédiés, j'ai moi-même dû le faire sur mon side-project de lib de data-binding. Mais en l'état, j'ai l'impression que Monkberry ne fait rien de tout ça et se contente d'une sorte de transpilation template HTML --> JS bête et méchante.

    Bref j'attends d'avoir plus de retours et des démos réelles d'applications pour juger, mais je suis très mitigé pour le moment.
    One Web to rule them all

  9. #9
    Membre éclairé
    Merci pour l'analyse.

    Citation Envoyé par SylvainPV Voir le message
    C'est bien du data-binding, à partir du moment où il y a des mises à jour partielles du DOM et une résolution des liaisons dans un modèle de données.
    Le data binding n'implique-t-il pas par définition une synchronisation automatisée ? Ici, après chaque modification des données, il faut faire un :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    view.update(state);


    Citation Envoyé par SylvainPV Voir le message
    C'est un peu comme si vous écriviez vos mises à jour du DOM à la main, sauf que là c'est un compilateur qui s'en charge.
    C'est-à-dire que Monkberry donne un langage de template à ceux qui veulent gérer des morceaux du DOM à l'ancienne.

    Citation Envoyé par SylvainPV Voir le message
    Vu que la latence réseau reste le problème de perf numéro 1 pour l'usage web, le fait que la précompilation vienne décupler la taille des templates est un énorme désavantage
    Ah, effectivement. D'expérience, en ce qui me concerne, le poids des templates dans une application JS n'est pas énorme relativement au code JS, mais c'est un point à vérifier.

    Citation Envoyé par SylvainPV Voir le message
    J'ai aussi de grosses craintes sur la résolution de divers problèmes tels que les boucles infinies ou la résistance aux modifications inopinées du DOM. C'est le genre de chose pour lesquels Angular/React/Vue ont des mécanismes dédiés, j'ai moi-même dû le faire sur mon side-project de lib de data-binding. Mais en l'état, j'ai l'impression que Monkberry ne fait rien de tout ça et se contente d'une sorte de transpilation template HTML --> JS bête et méchante.
    Boucles infinies : il faudrait que je vois un exemple, je ne comprends pas où est le risque.
    Pour les modifications inopinées du DOM : il me semble aussi que rien n'est géré.

  10. #10
    Rédacteur/Modérateur

    Il faut voir ce que l'on entend par "synchronisation automatisée". Je décompose ça en trois points: détection de changements, résolution des liaisons et mise à jour du DOM. Le data-binding désigne surtout la partie intermédiaire qui relie modèle et DOM, à partir de là on a des techniques de change detection et de mises à jour du DOM très différentes selon les solutions comme vu dans l'article. Les React / Redux / Vuex et autres Flux-based fonctionnent tous avec une API de changement d'état par exemple.

    Pour les boucles infinies j'en parle en début de l'article.
    One Web to rule them all

  11. #11
    Membre éclairé
    Citation Envoyé par SylvainPV Voir le message
    Pour les boucles infinies j'en parle en début de l'article.
    Le 2-way data binding pose plusieurs problématiques, dont la principale est celle de provoquer des boucles infinies dans certains cas. Un match de ping-pong peut survenir lorsqu'une mise à jour du modèle entraîne une mise à jour de la vue qui elle-même entraîne une mise à jour du modèle, qui elle-même entraîne une mise à jour de la vue, etc.
    Sauf erreur, cette problématique est en dehors du scope de Monkberry, puisqu'il n'y a pas de détection des changements. Et pas non plus de mise à jour automatisée d'un état à partir de valeurs d'un formulaires. Ici, c'est au développeur de faire attention à ce qu'il fait.

  12. #12
    Rédacteur/Modérateur

    Le fait que Monkberry ne fasse pas de 2-way data-binding réduit les risques, c'est sûr, mais il y a d'autres manières de provoquer des boucles infinies: listeners d'évènements, hooks, setters... . La raison pour laquelle j'associe 2-way d-b avec boucles infinies dans l'article, c'est que ce mécanisme induit beaucoup d'opérations discrètes qui peuvent échapper au développeur et le surprendre, d'où l'émergence de bugs / boucles infinies. Mais ce n'est pas le 2-way d-b qui est à l'origine du problème, c'est juste un facteur aggravant car plus complexe à appréhender par le développeur. Au final, c'est toujours au développeur de faire attention et de se corriger, qu'il y ait un mécanisme de prévention ou non.

    Pour reprendre l'exemple de l'article avec Monkberry et provoquer une boucle infinie de façon naïve : http://jsfiddle.net/65re07Ls/1/
    One Web to rule them all

###raw>template_hook.ano_emploi###