JSON ?

JSON ! c’est le cri de tous les développeurs web à la mode dès qu’ils entendent parler d’échanges de données. Ce format est sensé être plus performant, plus simple, plus standard, plus performant, plus web 2.0 quoi.

Plusieurs points mériteraient un billet à part entière, et je suis en désaccord sur chacun d’eux, mais je me focaliserai ici sur un seul : la performance. Les performances peuvent se voir au niveau du téléchargement et au niveau de l’interprétation par le client.

Formats d’échange

Nous avons trois formats d’échanges courants : JSON, XML, et HTML

JSON est apparu car il est simple à interpréter avec eval(). Maintenant dès qu’il y a un risque que quelqu’un d’autre puisse manipuler les données, il y a un problème de sécurité. On utilise donc couramment des bibliothèques Javascript externes. Ces bibliothèques analysent la chaîne json à coup d’expression rationnelles. Il existe aussi un bibliothèque d’analyse JSON native dans Firefox mais elle n’est accessible sans privilèges ni dans la version 2 ni dans la version 3. Je ferai la différence entre les trois en parlant de JSON+regexp, JSON+eval et JSON+firefox. 

XML est plus classique. A priori en Javascript vous utilisez DOM pour l’analyser. Sur les navigateurs récents ça sera peut être du E4X. Si votre but est de sortir du HTML, vous pouvez aussi utiliser le moteur XSLT des navigateurs. Là aussi, si besoin on séparera XML+dom, XML+e4x et XML+xslt.

Enfin, renvoyer une grosse chaîne HTML reste toujours faisable. S’il faut encore extraire des valeurs rien n’empêche d’avoir du XHTML. Vous bénéficier de DOM si besoin et vous pouvez envoyer ça directement dans vos pages HTML sans y toucher.

Taille à télécharger

La même données est plus petite en JSON qu’en XML. Pour chaque élément le nom de la donnée est présent une fois en JSON, et deux fois (ouverture + fermeture) en XML. Par contre la différence n’est pas aussi importante qu’on le croit. Alexis Moussine-Pouchkine trouve qu’en moyenne JSON est 40% plus petit que XML. Des test rapides de mon côté me donnent des chiffres légèrement moins optimistes, vers les 35%. Je garderai 40% par précaution.

40% c’est en même temps énorme et pas grand chose. C’est énorme en soi mais les données transférées sont généralement petites. Si on part sur une donnée de 2ko, la différence sera de 800 octets. C’est notable mais pas important non plus. C’est même probablement négligeable face au reste. 

Reste encore que XML et JSON sont tous les deux des formats qui se compressent très très bien. Si on espère un ratio de compression de 20%, nos 2ko deviennent moins de 500 octets. À ce niveau même si le ratio JSON/XML restait le même, le gain serait proche de 160 octets. Si on compte la requête et les entêtes de réponse (entre 1ko et 1.5ko), on a un gain total de 160 octets sur environ 2ko. Autant dire que ce n’est pas significatif. 

Pour que ce soit significatif (1ko de différence), il faudrait que notre XML fasse environ 12ko. Ca reste assez rare. JSON et XML à égalité ou presque sur ce point là.  

Oui mais…

Oui mais on a parlé de JSON+lib, qui est la technique sans problèmes de sécurité. Et là il faut une bibliothèque externe à télécharger. La plus courante est celle de Douglas Crockford qui fait 12ko décompressé. Celle de YUI a sensiblement la même taille. Là même zippé il restera un nombre à 4 chiffres. Ca devient vraiment gênant si vous n’arrivez pas à fusionner ce fichier avec vos autres fichiers javascript : là vous aurez une requête HTTP de plus, avec la latence et les problème de rendu bloqués que ça implique.

Finalement la différence est vraiment légère mais à l’avantage de XML. JSON vous demandera au mieux 1ko de plus une fois minifié et gzipé.

Temps à analyser

C’est là qu’on s’amuse. XML est lent à interpréter, c’est connu par tous et je ne le contesterai certainement pas. Maintenant JSON l’est aussi, et ça c’est moins accepté. L’utilisation de eval() demande à javascript lancer un nouvel interpréteur et empêche le moteur d’optimiser tout ce qu’il y a autour du eval(). C’est lent, spécialement sur Microsoft Internet Explorer. JSON+lib est malheureusement encore pire vu que l’interprétation se fait cette fois ci en pur javacript.

D’autres que moi ont fait des tests. Un premier test trouve XML+dom deux fois plus rapide que JSON+eval. Dave Johnson des graphiques intéressants en fonction du nombre d’éléments dans le jeu de données. Du plus rapide au plus lent sous Microsoft Internet Explorer 6 il trouve XML+xslt, XML+dom et enfin JSON+eval. Sous Firefox 1.5 c’est JSON+eval qui est plus rapide mais la différence est moitié moins importante. En considérant un marché français de 25% de Firefox, JSON+eval est en moyenne nettement plus lent.

J’aimerais trouver des comparatifs de performance avec XML+e4x. La différence risque de s’agrandir d’autant plus. Il faut aussi ajouter qu’un appel à XMLHttpRequest.responseText serait environ deux fois plus lent qu’un appel à XMLHttpRequest.responseXML. Je ne comprend pas pourquoi et je n’ai pas vérifié la validité de l’affirmation mais cela se rajouterait encore à la différence, en faveur de XML.

Reste à vérifier si cette différence de performance est significative. Le premier test est fait sur 10000 entrées pour un gain de 15ms (sur le second test on ne connait pas le temps pris par chaque itération). Peut être qu’un support natif dans dans les navigateurs fera la différence dans quelques années. Pour l’instant, même si JSON est plus lent, les différences ne sont pas significatives.  

Oui mais…

Oui mais là aussi je n’ai pas pris en compte JSON+lib. Il faut non seulement interpréter les 12ko de javascript au départ mais ensuite faire tourner le moteur basé sur des expressions rationnelles. Il y a mieux. C’est toujours Dave Johnson qui nous propose un comparatif entre JSON+lib, JSON+eval et XML+xslt. Il y a un monde entre JSON+lib et JSON+eval, quel que soit le navigateur. Même avec peu d’itérations, on voit les temps monter significativement dans le test JSON+lib.

Pire, sous Microsoft Internet Explorer et avec JSON, le temps nécessaire pour l’analyse évolue en factorielle avec le nombre d’éléments dans les données. Ca c’est disqualifiant. Plus la données est grosse, plus la différence de performance entre JSON et XML augmente. Une augmentation non linéaire est rarement négligeable.

Plus haut je disais que sur plus de 10ko la différence de téléchargement devenait significative en faveur de JSON. Mais avec ces résultats on voit aussi que la différence de temps de traitement le devient aussi, dans le sens opposé. La différence de taille évoluant linéairement et la différence de temps de traitement évoluant de manière factorielle, JSON ne sera jamais plus performant. N’oublions pas que pendant que Javascript est exécuté, c’est toute l’interface qui ne répond plus.

Alors ?

Alors quoi ? Alors déjà il faudrait un peu plus de test. J’en ferai peut être si je ne trouve rien de suffisamment complet. Il faudrait par exemple vérifier si le mauvais à priori du à évolution en factorielle et mauvaise performance des bibliothèques javascript pour JSON se traduit par des valeurs significatives ou pas. Si ça se joue au final à quelques dizaines de millisecondes par exécution c’est négligeable, si ça dépasse la demi-seconde ça ne l’est peut être pas.

Ceci dit, en attendant, je peux affirmer une chose claire : JSON n’a aucun avantage côté performance. XML se payerait même le luxe d’être au moins légèrement plus performant, à cause de sa gestion native dans les navigateurs.

Cette petite étude ne me permet pas de refuser JSON, par contre elle me permet de commencer à douter de ses soit-disant avantages. XML est présent partout, dans tous les langages, dans la plupart des applications. Il gagnera toujours les points compatibilité, extensibilité et pérennité. Est-ce que ça vaut vraiment la peine de s’embêter avec JSON sur le web tant qu’il n’y a pas d’avantages de performance ?           

20 réflexions au sujet de « JSON ? »

  1. Neovov

    « XML se payerait même le luxe d’être au moins légèrement plus performant, à cause de sa gestion native dans les navigateurs »

    J’aurai plutôt dit « grâce à sa gestion native » :P

    Et justement, ça doit être pour ça que JSON est moins performant que XML, puisqu’il reste artisanal (un gros eval c’est un peu crados), peut-être que si les navigateurs proposaient des méthodes pour exploiter du JSON les résultats seraient différents.

    (mais je doute que les développeurs de navigateurs veuillent se pencher là dessus…)

    Merci pour cet article, je bois tes conseils ;) !

  2. Éric

    Ils s’y attachent. Voir http://starkravingfinkle.org/blog/2008/02/extension-developers-native-json-parsing/ et http://developer.mozilla.org/en/docs/nsIJSON

    Mais pour Firefox il faut encore les privilèges chrome, ce qui empêche toute utilisation sur un site web classique. Ca ne changera pas pour Firefox 3. D’ici à Firefox 4, d’ici à ce que les autres navigateurs et particulièrement MSIE proposent quelque chose d’équivalent … il y aura de l’eau sous les ponts.

    Entre temps E4X arrive, et XML pourrait regagner le coeur des développeurs.

  3. Sunny

    J’aimerais ajouter dans le sens de JSON que si l’on fait totalement confiance à sa source, aucun besoin de librairie externe, juste d’un eval(). Ceci permet de traiter des données aussi simplement que eval(mon_json).livres[3].auteurs[0].adresse.ville.

  4. Rik

    On dérive un peu du sujet initial, mais considérer ses données comme non sûres permet d’éviter, en cas de laxisme à un endroit de ton appli, de contaminer toute l’appli.

  5. Éric

    Je n’ai pas testé, mais je serai étonné que passer par un <script> soit plus performant qu’un eval(). En interne ça doit être assez similaire à traiter.

  6. Louis

    @Rik: bien dit concernant la sécurité. Si l’on encrypte ses tables utilisateurs dans sa base de données, c’est pour la même raison : si jamais quelqu’un y a accès — quand bien même on a tout fait pour éviter ce scénario— cette mesure permet de limiter les dégats.

    Il toujours bon dans le cadre de scripts web de prévoir des sas de sécurité afin de limiter la casse en cas de coups durs.

  7. stef13013

    Article très intéressant…
    Cependant, en passant, je ne comprends pas très bien une chose:
    Vous dites ques le performances d’un site sont très importantes (tout à fait d’accord) mais cela ne semble pas vous emballer outre mesure que les datas de JSON soit 35/40% plus compactes.

    Etonnant :)

    Mais super article tout de même

  8. Éric

    C’est dit dans le texte. La question n’est pas le pourcentage de différence mais la valeur absolue : combien d’octets sont effectivement téléchargés en plus.

    Je pars sur une donnée de 2ko qui me parait représentative, mais on peut refaire le calcul avec d’autres chiffres la conclusion restera assez similaire. Sur un XML de 2ko, une fois passé par gzip, l’équivalent json+gzip la différence en valeur absolue est d’environ 160 octets. La différence de poids entre XML et JSON pour le type de données qu’on transfère habituellement est franchement négligeable devant le poids de la requête HTTP elle-même.

    Bref, on gagne d’un côté 160 octets négligeables face à ce qui est transmis par ailleurs, mais on perd bien plus en devant ajouter une bibliothèque javascript de décodage ou simplement en utilisant eval().

    Replacé dans son contexte, la différence de poids est peu significative.

  9. stef13013

    Ok, vous avez raison… mais votre comparaison se base sur le fait que XML est géré nativement par le browser et pas JSON.
    Cela revient un peu à comparer du P-CODE avec du code compilé :)
    Bon j’exagère un peu mais quand même.

    Wait and see…

  10. Éric

    Tout à fait. Ce n’est pas une qualité intrinsèque de Json ou de Xml, mais plus l’environnement qu’il y a autour. Le jour où Json sera interprété nativement par 80% du marché des navigateurs (ça arrive, ça arrive) alors cet article n’aura plus de sens.

  11. Ninj

    Ah tiens, cet article n’a plus de sens :)

    Je provoque, il reste intéressant, mais les grands navigateurs intègrent maintenant un objet JSON nativement. Alors justement, il serait très intéressant d’étayer ce texte avec de nouveaux petits tests je trouve.

    Par ailleurs, bien que globalement d’accord avec les conclusions de l’article, je trouve la démonstration incroyablement orientée, et très peu objective. Elle minimise puis occulte ouvertement chaque éléments contraires à la conclusion recherchée, les uns après les autres, pour finalement aboutir, par la force des choses, à la conclusion qu’aucun n’est viable.

    Je noterai quand même, dans le désordre,
    qu’une librairie externe JS est rarement re-téléchargée à chaque page ;
    que 40% en taille, quoi qu’on en dise sur la valeur absolue, c’est énorme (pourquoi supposer qu’on ne transmet que de toutes petites données, et qu’est-ce qu’on appelle petites données ? Pour moi, 800 octets c’est gros quand c’est une différence que l’on trouve dans chaque objet passé !) ;
    etc.

    Dans « Ridicule », un professeur démontre au roi l’existence de Dieu. Il termine sa démonstration sous les applaudissement du roi par cette phrase, qui lui vaudra la mort : « j’aurais pu tout aussi bien démontrer le contraire si son Altesse me l’avait demandé »…

    Enfin, bon travail de documentation cependant, merci ;)

  12. Éric

    Oui, il faudrait mettre à jour maintenant.

    Par contre pour la taille tu ne peux pas faire attention à quelques octets qui sont finalement très léger en valeur absolue, et en même temps considérer comme négligeable l’import de la bibliothèque.

    Même avec le cache, c’est dans les 40% des utilisateurs qui téléchargeront la lib une fois au cours de leur visite. Il va falloir faire beaucoup de json pour compenser.

    Mais même si ça compense, entre télécharger un gros morceau, une fois, de manière bloquante, et télécharger plein de petites fois quelques octets de plus, au fil de l’eau, je te garantis que tu verras passer le premier cas mais que le second ne se verra pas du tout.

    Pour qualifier de petit :
    – Moins de 1.4Ko ça passe dans un seul segment TCP, c’est virtuellement identique que tu transfères 300 octets ou 1Ko. Pour voir une différence il faudrait que ces messages de 300 octets arrivent à saturer la bande passante disponible. Sur une connexion TCP saturer la bande passante avec des messages d’un seul segment est quasiment impossible, il faudrait que tu en envoies des milliers en simultané et en continu sur ton navigateur. Si ton navigateur envoit 5 requêtes ajax en simultané il y a déjà probablement un problème de conception ou d’agrégation donc on a de la marge.

    – En dessous de 4Ko ça passe dans moins de trois segments TCP, donc ça passe en un seul round trip, sans attendre les ACK TCP. Là aussi, même chose, pour saturer il en faudrait quelques milliers à la fois.

    Donc voilà, si ton message ne dépasse pas les 5 Ko (et je doute qu’il le fasse) tu ne verras pas la différence. Tant qu’il ne dépasse pas les 20 Ko et que tu as une faible latence, la différence sera négligeable vu qu’on parle de requêtes en fond, non bloquantes.

    Et non, si tu considères que 40% c’est énorme sans regarder la valeur absolue c’est toi qui a un problème de raisonnement.

  13. Guibert

    Sympa l’article, je serais moins « catégorique » car tout dépend du site et de son usage.

    Si vous prenez en compte le trafic total d’un site, genre 1 millions de visite par jour, même 1%, même 3 octets peuvent au final économiser quelques téraoctet par jour.

    Il n’y a pas de « plus ou mieux que ». C’est surtout une question de meilleurs choix en fonction de l’ensemble des contraintes techniques/financières/humaine.

    Une des lacunes de json par rapport au XML, c’est l’absence de « schéma ». Mais est-ce qu’un schéma est bien nécessaire pour l’usage qui en est fait ?

    Bref, le temps passe et SOAP disparaîtra :-)

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>