Bonjour,

je m'interroge, investis du temps et fais quelques tests de faisabilité autour d'une bibliothèque de gestion de DOM virtuel "maison". J'ai besoin d'avis de personnes agueries aux structures de données complexes et autres frameworks tels que React / Redux / Preact / Skatejs.

Ce post est assez long, je m'efforce de le segmenter au mieux. Une simple remarque ou un encouragement peuvent être utiles donc n'hésitez pas...

Mon idée de base est de stocker l'arborescence du markup de l'appli (nieuds et attributs pour commencer) dans un pool linéaire unique de blocks identiques. Les opérations de diff / patch se feraient à partir de cette structure unique. Ce sont des modifications "in-place" mais en mémoire, pas dans le DOM, à part le moment de patcher.

Pourquoi cela :

- pour faciliter la persistance dans une BDD locale ou distante de blocs identiques (facilité de sérialisation)

- pour éviter / minimiser les cycles de garbage collector inhérents à chaqeue création d'arbre + destruction du précédent

- pour permettre le time-travelling de l'application : possibilité de rejouer des scénatrios, de mettre en pause en cas d'erreur, etc.

- parce que c'est un excelllent exercice de style et que c'est cool de tenter !

EDIT: accessoirement cela permettrait de stocker l'image (au sens sérialisation) applicative à un instant T. Du coup dans une application hybride de type Cordova; cela permettrait de détecter l'obsolescence de l'appli et de faire sa mise à jour sans passer ni par le store d'appli, ni par un quelconque service tiers de code psuh... le conteneur n'aura qu'à requêter de temps à autre le serveur (une fois par semaine ou tous les x utilisations...) en comparant le hash de la version courante, et celle qu'il a en cache... et le tour sera joué (attention #yakafaucon !)

Je ne suis pas un grand expert de la programation fonctionnelle réactive, aussi mes tests sont ils exprimés de façon impérative.

Concrètement j(ai défini une unité de base, le BLOCK objet "propeerty bag" ayant pour signature :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
 
    let block = ( ) => {
      UID : ...,   // identifiant unique dans le blocks pool
      PUID : ...   // identifiant du block parent
      kind: ...    // ce qu'in stocke dans ce block TAG, TEXT, ATTRIBUTE, CODE ..
      rank: 0     // rang dans la fratrie (child sibling rank)
      name: 'div' // nom de l'élément stocké.  Pour les tags par exemple, et les attributs
      value: ''   // valuer pour les attributs et les noeuds texte ou code
      used: true  // idndique si le bloc est à utluser ou à recycler
    }
EDIT: le tri topologique de l'arbre pour permettre son affichage text dans une console par exemple se ferait beaucoup plus simplement avec l'ID du premier ATTRibut, l'ID du premier fils et l'ID du prochain de fratrie =... cela fait 3 clés * 4 octets = 12 octets de plus par bloc !

Le pool est un autre object bag contenant :

- une liste de blocks "blocks", utilsés ou non, et de taille variable, pouvant croître de 25% à chaque réallocation;

- une entrée "lookup" : hash object ou une map dont les clés sont des UIDs et les valeurs des blocks, permet de garantir un temps d'accès constant aux blocks de la liste, au prix d'un léger surcout de mémoire que je pense pouvoir compenser par la suite grâce au côté in-place des traitements

- une liste "reldased" stockant et permettant de dépiler (pop) des blocs libres quand c'est nécessaire

Le pool a donc basiquement cette structure :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
 
    const pool = {
      blocks: [],
      lookup : {},
      released : []
    }
Il y aura surement quelque part un éspece de swap (pile ou queue) pour, manoeuvrer temportairement les blocs lors des traitements.

Comme les blocks sont effectivement stockés dans la liste, le surcôut mémoire provient essentuiellement des clés de la lookup... un bloc créé dans la liste est seulement référencé dans la lookup et peuit etre dans la liste "released" des blocs libres.

Les UIDs sont des clés de 4 digits sur de 6 bits (64 valuers) = 24 bits en tout, lisibles et compatibles avec un identifiant ( a-zA-Z0-9_$ ) et sont générés de façon pseudo aléatoire à partir d'un générateur congruentiel linéaire à cycle complet, d'après une graine définie par l'utulusatuer, par composant.

la fonction hyperscript "h" peut être écrite telle quelle dans le code, ou à partir de JSX ou mieux encore à partir de chaînes de template Jade/PUG, car j'aime beaucoup ce format... ce sera l'ojbet d'un développement ultérieur, le temps d'étudier le fonctionnement de leurs lexer et parser.

La fonction "h" devra appartenir à une closure javascript, histoire de pouvoir redirger l'ensemble ses compositions d'appel, par composant et pour l'application sur le même pool de blocks.

Exemples:

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
18
19
20
21
22
23
24
25
 
    const h = meom('cle-user-par-composant')
 
    const view1 = ()data =>
      h('div', { 'id': 'contanier'}, 
        h('h1'), {}, 'my-awesome-vsom-lib'),
        h('ul', {},
          h('li', { 'class': 'active'}, 'highlighted text !'),
          h('li', { }, 'awesome text' ),
          h('li', { }, 'another text )'
        )
      )
 
 
     // ou si on arrive a déternourner PUG/Jade
     const h = meom('cle-user-par-composant')
 
     // ES2015 tagged template string
     pug2memo `div#container
       h1 my-awesome-vdom-lib
       ul
         li (class="active") higligted text
         li awesome text
         another text         
     `
oug2dom utilisera le lexer de PUG pour emballer les définitions de fonctions "h" dans le 2eme exemple pour obtenir ce qu'on voit dans le premier. Notez l'appel à memo() au début de chauqe exemple pour obtneir une fonction hyperscript "h" liée par closure à une partie du pool référencée par le hash de la chaîne 'cle-user-par composant.

Encore une fois je répète TOUT les appels à "h"' doivent se traduire par un stockage dans lamême structure de pool... A ce point je vais demander mles avis des uns et des autres sur la faisabilité d'un tel projet. N(hésitez pas à me poser des questions pour plus de détails.

Je vais préparer un dépôt pour stocker le résultat de mes tests en cas de demande. Mes récents posts sur le forum 'Général Javascript' se rapportent à ce projet.

salut, A + F - E