portaldacalheta.pt
  • Principal
  • Design De Marque
  • Personnes Et Équipes Produit
  • Innovation
  • Kpi Et Analyses
La Technologie

Sérialisation d'objets complexes en JavaScript



Performances du site Web et mise en cache des données

Les sites Web modernes récupèrent généralement des données à partir d'un certain nombre d'emplacements différents, y compris des bases de données et des API tierces. Par exemple, lors de l'authentification d'un utilisateur, un site Web peut rechercher l'enregistrement utilisateur dans la base de données, puis l'embellir avec des données provenant de certains services externes via des appels d'API. La minimisation des appels coûteux à ces sources de données, tels que l'accès au disque pour les requêtes de base de données et les allers-retours Internet pour les appels d'API, est essentielle pour maintenir un site rapide et réactif. La mise en cache des données est une technique d'optimisation courante utilisée pour y parvenir.

Les processus stockent leurs données de travail en mémoire. Si un serveur Web s'exécute dans un seul processus (tel que Node.js / Express), ces données peuvent facilement être mises en cache à l'aide d'un cache mémoire exécuté dans le même processus. Cependant, les serveurs Web à charge équilibrée couvrent plusieurs processus et, même lorsque vous travaillez avec un seul processus, vous souhaiterez peut-être que le cache persiste au redémarrage du serveur. Cela nécessite une solution de mise en cache hors processus telle que Redis, ce qui signifie que les données doivent être sérialisées d'une manière ou d'une autre et désérialisées lorsqu'elles sont lues à partir du cache.



La sérialisation et la désérialisation sont relativement simples à réaliser dans des langages à typage statique tels que C #. Cependant, la nature dynamique de JavaScript rend le problème un peu plus délicat. Alors qu'ECMAScript 6 (ES6) a introduit les classes, les champs de ces classes (et leurs types) ne sont pas définis tant qu'ils ne sont pas initialisés - ce qui peut ne pas être le cas lorsque la classe est instanciée - et les types de retour de champs et de fonctions ne sont pas définis du tout dans le schéma. De plus, la structure de la classe peut facilement être modifiée au moment de l'exécution - des champs peuvent être ajoutés ou supprimés, des types peuvent être modifiés, etc. Bien que cela soit possible en utilisant la réflexion en C #, la réflexion représente les «arts sombres» de ce langage, et les développeurs s'attendent à ce qu'il brise les fonctionnalités.



J'ai été confronté à ce problème au travail il y a quelques années lorsque je travaillais dans l'équipe principale d'ApeeScape. Nous construisions un tableau de bord agile pour nos équipes, qui devait être rapide; sinon, les développeurs et les propriétaires de produits ne l'utiliseront pas. Nous avons extrait des données d'un certain nombre de sources: notre système de suivi du travail, notre outil de gestion de projet et une base de données. Le site a été construit en Node.js / Express, et nous avions un cache mémoire pour minimiser les appels à ces sources de données. Cependant, notre processus de développement rapide et itératif nous a permis de déployer (et donc de redémarrer) plusieurs fois par jour, invalidant le cache et perdant ainsi bon nombre de ses avantages.



Une solution évidente était un cache hors processus tel que Redis . Cependant, après quelques recherches, j'ai trouvé qu'il n'existait pas de bonne bibliothèque de sérialisation pour JavaScript. Les méthodes intégrées JSON.stringify / JSON.parse renvoient des données du type d'objet, perdant toutes les fonctions sur les prototypes des classes d'origine. Cela signifiait que les objets désérialisés ne pouvaient pas simplement être utilisés «en place» dans notre application, ce qui nécessiterait donc une refactorisation considérable pour fonctionner avec une conception alternative.

Exigences pour la bibliothèque

Afin de prendre en charge la sérialisation et la désérialisation de données arbitraires en JavaScript, avec les représentations désérialisées et les originaux utilisables de manière interchangeable, nous avions besoin d'une bibliothèque de sérialisation avec les propriétés suivantes:



  • Les représentations désérialisées doivent avoir le même prototype (fonctions, getters, setters) que les objets d'origine.
  • La bibliothèque doit prendre en charge les types de complexité imbriqués (y compris les tableaux et les cartes), avec les prototypes des objets imbriqués correctement définis.
  • Il doit être possible de sérialiser et de désérialiser les mêmes objets plusieurs fois - le processus doit être idempotent.
  • Le format de sérialisation doit être facilement transmissible via TCP et stockable à l'aide de Redis ou d'un service similaire.
  • Des modifications minimales du code doivent être requises pour marquer une classe comme sérialisable.
  • Les routines de la bibliothèque doivent être rapides.
  • Idéalement, il devrait y avoir un moyen de prendre en charge la désérialisation des anciennes versions d'une classe, par le biais d'une sorte de mappage / contrôle de version.

la mise en oeuvre

Pour combler cette lacune, j'ai décidé d'écrire Tanagra.js , une bibliothèque de sérialisation à usage général pour JavaScript. Le nom de la bibliothèque fait référence à l'un de mes épisodes préférés de Star Trek: la nouvelle génération , où l'équipage du Entreprise doit apprendre à communiquer avec une mystérieuse race extraterrestre dont la langue est inintelligible. Cette bibliothèque de sérialisation prend en charge les formats de données courants pour éviter de tels problèmes.

Tanagra.js est conçu pour être simple et léger, et il prend actuellement en charge Node.js (il n'a pas été testé dans le navigateur, mais en théorie, cela devrait fonctionner) et les classes ES6 (y compris Maps). L'implémentation principale prend en charge JSON et une version expérimentale prend en charge les tampons de protocole Google. La bibliothèque ne nécessite que du JavaScript standard (actuellement testé avec ES6 et Node.js), sans dépendance aux fonctionnalités expérimentales, Babel transpiling, ou Manuscrit .



Les classes sérialisables sont marquées comme telles avec un appel de méthode lorsque la classe est exportée:

module.exports = serializable(Foo, myUniqueSerialisationKey)



La méthode renvoie un Procuration à la classe, qui intercepte le constructeur et injecte un identifiant unique. (S'il n'est pas spécifié, la valeur par défaut est le nom de la classe.) Cette clé est sérialisée avec le reste des données et la classe l'expose également en tant que champ statique. Si la classe contient des types imbriqués (c'est-à-dire des membres dont les types nécessitent une sérialisation), ils sont également spécifiés dans l'appel de méthode:

module.exports = serializable(Foo, [Bar, Baz], myUniqueSerialisationKey)



(Les types imbriqués pour les versions précédentes de la classe peuvent également être spécifiés de la même manière, de sorte que, par exemple, si vous sérialisez un Foo1, il puisse être désérialisé en un Foo2.)

Lors de la sérialisation, la bibliothèque crée de manière récursive une carte globale des clés vers les classes et l'utilise lors de la désérialisation. (N'oubliez pas que la clé est sérialisée avec le reste des données.) Afin de connaître le type de la classe «de premier niveau», la bibliothèque exige que cela soit spécifié dans l'appel de désérialisation:



const foo = decodeEntity(serializedFoo, Foo)

Une bibliothèque expérimentale de mappage automatique parcourt l'arborescence des modules et génère les mappages à partir des noms de classe, mais cela ne fonctionne que pour les classes nommées de manière unique.

Disposition du projet

Le projet est divisé en plusieurs modules:

  • tanagra-core - fonctionnalité commune requise par les différents formats de sérialisation, y compris la fonction de marquage des classes comme sérialisable
  • tanagra-json - sérialise les données au format JSON
  • tanagra-protobuf - sérialise les données au format protobuffers Google (expérimental)
  • tanagra-protobuf-redis-cache - une bibliothèque d'aide pour stocker des protobufs sérialisés dans Redis
  • tanagra-auto-mapper - parcourt l'arborescence des modules Node.js pour créer une carte de classes, ce qui signifie que l'utilisateur n'a pas à spécifier le type vers lequel désérialiser (expérimental).

Notez que la bibliothèque utilise l'orthographe américaine.

Exemple d'utilisation

L'exemple suivant déclare une classe sérialisable et utilise le module tanagra-json pour la sérialiser / désérialiser:

const serializable = require('tanagra-core').serializable class Foo { constructor(bar, baz1, baz2, fooBar1, fooBar2) { this.someNumber = 123 this.someString = 'hello, world!' this.bar = bar // a complex object with a prototype this.bazArray = [baz1, baz2] this.fooBarMap = new Map([ ['a', fooBar1], ['b', fooBar2] ]) } } // Mark class `Foo` as serializable and containing sub-types `Bar`, `Baz` and `FooBar` module.exports = serializable(Foo, [Bar, Baz, FooBar]) ... const json = require('tanagra-json') json.init() // or: // require('tanagra-protobuf') // await json.init() const foo = new Foo(bar, baz) const encoded = json.encodeEntity(foo) ... const decoded = json.decodeEntity(encoded, Foo)

Performance

J'ai comparé les performances des deux sérialiseurs (le JSON sérialiseur et expérimental protobufs sérialiseur) avec un contrôle (natif JSON.parse et JSON.stringify). J'ai mené un total de 10 essais avec chacun.

J'ai testé ceci sur mon 2017 Dell XPS15 ordinateur portable avec 32 Go de mémoire, exécutant Ubuntu 17.10.

J'ai sérialisé l'objet imbriqué suivant:

foo: { 'string': 'Hello foo', 'number': 123123, 'bars': [ { 'string': 'Complex Bar 1', 'date': '2019-01-09T18:22:25.663Z', 'baz': { 'string': 'Simple Baz', 'number': 456456, 'map': Map { 'a' => 1, 'b' => 2, 'c' => 2 } } }, { 'string': 'Complex Bar 2', 'date': '2019-01-09T18:22:25.663Z', 'baz': { 'string': 'Simple Baz', 'number': 456456, 'map': Map { 'a' => 1, 'b' => 2, 'c' => 2 } } } ], 'bazs': Map { 'baz1' => Baz { string: 'baz1', number: 111, map: Map { 'a' => 1, 'b' => 2, 'c' => 2 } }, 'baz2' => Baz { string: 'baz2', number: 222, map: Map { 'a' => 1, 'b' => 2, 'c' => 2 } }, 'baz3' => Baz { string: 'baz3', number: 333, map: Map { 'a' => 1, 'b' => 2, 'c' => 2 } } }, }

Écrire des performances

Méthode de sérialisation Ave. inc. premier essai (ms) StDev. inc. premier essai (ms) Ave. ex. premier essai (ms) StDev. ex. premier essai (ms)
JSON 0,115 0,0903 0,0879 0,0256
Google Protobufs 2,00 2 748 1.13 0,278
Groupe de contrôle 0,0155 0,00726 0,0139 0,00570

Lis

Méthode de sérialisation Ave. inc. premier essai (ms) StDev. inc. premier essai (ms) Ave. ex. premier essai (ms) StDev. ex. premier essai (ms)
JSON 0,133 0,102 0,104 0,0429
Google Protobufs 2,62 1.12 2,28 0,364
Groupe de contrôle 0,0135 0,00729 0,0115 0,00390

Sommaire

La JSON le sérialiseur est environ 6 à 7 fois plus lent que la sérialisation native. L'expérimental protobufs le sérialiseur est environ 13 fois plus lent que le JSON sérialiseur, ou 100 fois plus lent que la sérialisation native.

En outre, la mise en cache interne des informations de schéma / structure dans chaque sérialiseur a clairement un effet sur les performances. Pour le sérialiseur JSON, la première écriture est environ quatre fois plus lente que la moyenne. Pour le sérialiseur protobuf, il est neuf fois plus lent. Ainsi, l'écriture d'objets dont les métadonnées ont déjà été mises en cache est beaucoup plus rapide dans l'une ou l'autre des bibliothèques.

Le même effet a été observé pour les lectures. Pour la bibliothèque JSON, la première lecture est environ quatre fois plus lente que la moyenne, et pour la bibliothèque protobuf, elle est environ deux fois et demie plus lente.

Les problèmes de performances du sérialiseur protobuf signifient qu'il est encore au stade expérimental, et je le recommanderais uniquement si vous avez besoin du format pour une raison quelconque. Cependant, cela vaut la peine d'investir du temps, car le format est beaucoup plus laconique que JSON, et donc meilleur pour l'envoi par fil. Stack Exchange utilise le format pour sa mise en cache interne.

Le sérialiseur JSON est clairement beaucoup plus performant mais toujours nettement plus lent que l'implémentation native. Pour les petites arborescences d'objets, cette différence n'est pas significative (quelques millisecondes en plus d'une requête de 50 ms ne détruiront pas les performances de votre site), mais cela pourrait devenir un problème pour les arborescences d'objets extrêmement grandes, et c'est l'une de mes priorités de développement.

Feuille de route

La bibliothèque est encore en phase bêta. Le sérialiseur JSON est raisonnablement bien testé et stable. Voici la feuille de route pour les prochains mois:

  • Améliorations des performances pour les deux sérialiseurs
  • Meilleure prise en charge du JavaScript pré-ES6
  • Prise en charge des décorateurs ES-Next

Je ne connais aucune autre bibliothèque JavaScript qui prend en charge la sérialisation de données d'objets complexes et imbriqués et la désérialisation vers son type d'origine. Si vous mettez en œuvre une fonctionnalité qui bénéficierait de la bibliothèque, veuillez l'essayer, prendre contact avec vos commentaires et envisager de contribuer.

Page d'accueil du projet
Dépôt GitHub

combien y a-t-il de principes de gestalt

Comprendre les bases

Comment les objets sont-ils stockés dans JavaScript?

En général, les objets ne sont pas stockés. Ils sont instanciés en cas de besoin, utilisés dans le traitement, puis supprimés de la mémoire lorsqu'ils ne sont plus nécessaires. Si nous devons utiliser temporairement des données ailleurs, nous sérialisons et désérialisons ces données dans une autre structure.

Qu'est-ce qu'un objet JavaScript?

Un objet est un morceau de code qui encapsule une structure, ainsi que des opérations qui peuvent être effectuées sur cette structure. Généralement, c'est la même chose qu'un objet dans n'importe quel langage de programmation orienté objet.

Qu'est-ce qu'un objet de données?

Un objet de données est un morceau de code qui contient temporairement des données d'un magasin de données afin qu'il puisse être lu ou traité dans une application. Sauf s'il existe un moyen de conserver ces données en mémoire, elles sont réécrites ou non conservées lorsque l'objet sort de la portée ou n'est pas nécessaire.

Pourquoi avons-nous besoin d'une sérialisation et d'une désérialisation?

La sérialisation nous permet de conserver les données à utiliser dans le processus en cours d'exécution ou dans d'autres processus si nécessaire. Nous stockons les données, puis les désérialisons lorsqu'elles sont utilisées ailleurs.

Guide du développeur pour améliorer la structure de projet dans les applications Meteor

Back-End

Guide du développeur pour améliorer la structure de projet dans les applications Meteor
Qu'est-ce qu'un round down et comment en éviter un

Qu'est-ce qu'un round down et comment en éviter un

Investisseurs Et Financement

Articles Populaires
Ingénieur senior full-stack, équipe post-embauche des talents
Ingénieur senior full-stack, équipe post-embauche des talents
En souvenir de Matthew Osborne
En souvenir de Matthew Osborne
Comment créer un pipeline de déploiement initial efficace
Comment créer un pipeline de déploiement initial efficace
L'impact du Brexit sur le secteur des services financiers
L'impact du Brexit sur le secteur des services financiers
Comment préparer un modèle de tableau des flux de trésorerie qui s'équilibre réellement
Comment préparer un modèle de tableau des flux de trésorerie qui s'équilibre réellement
 
Conquérir la recherche de chaînes avec l'algorithme Aho-Corasick
Conquérir la recherche de chaînes avec l'algorithme Aho-Corasick
Estimation des coûts logiciels dans la gestion de projet agile
Estimation des coûts logiciels dans la gestion de projet agile
5 qualités indispensables des meilleurs chefs de projet
5 qualités indispensables des meilleurs chefs de projet
Comment recréer gratuitement les ressources d'un terminal Bloomberg
Comment recréer gratuitement les ressources d'un terminal Bloomberg
Noyaux d'arbres: quantification de la similitude entre les données structurées en arborescence
Noyaux d'arbres: quantification de la similitude entre les données structurées en arborescence
Articles Populaires
  • comparaison de s corp c corp llc
  • comment activer le bot discord
  • de quelle manière une balance commerciale négative peut-elle être convertie en une balance des paiements à 0 $ ?
  • la valorisation comparable au marché est basée sur le résultat net et le taux de capitalisation de la startup.
  • comment écrire des cas de tests unitaires en java
  • que sont les bots sur discord
Catégories
  • Design De Marque
  • Personnes Et Équipes Produit
  • Innovation
  • Kpi Et Analyses
  • © 2022 | Tous Les Droits Sont Réservés

    portaldacalheta.pt