Съвременните уебсайтове обикновено извличат данни от редица различни местоположения, включително бази данни и API на трети страни. Например, когато удостоверява потребител, уебсайт може да търси потребителския запис от базата данни, след което да го украси с данни от някои външни услуги чрез API повиквания. Минимизирането на скъпите обаждания към тези източници на данни, като достъп до диск за заявки към база данни и обратни пътувания до интернет за API повиквания, е от съществено значение за поддържането на бърз, отзивчив сайт. Кеширането на данни е често срещана техника за оптимизация, използвана за постигане на това.
Процесите съхраняват работните си данни в паметта. Ако уеб сървърът се изпълнява в един процес (като Node.js / Express), тогава тези данни могат лесно да бъдат кеширани с помощта на кеш памет, работещ в същия процес. Уеб сървърите с балансирано натоварване обаче обхващат множество процеси и дори когато работите с един процес, може да искате кешът да продължи, когато сървърът се рестартира. Това изисква решение за кеширане извън процеса, като Redis, което означава, че данните трябва да бъдат сериализирани по някакъв начин и десериализирани, когато се четат от кеша.
Сериализацията и десериализацията са относително лесни за постигане в статично типизирани езици като C #. Динамичното естество на JavaScript обаче прави проблема малко по-сложен. Докато ECMAScript 6 (ES6) въведе класове, полетата в тези класове (и техните типове) не се дефинират, докато не бъдат инициализирани - което може да не е, когато класът е инстанциран - и върнатите типове полета и функции не са дефинирани изобщо в схемата. Нещо повече, структурата на класа може лесно да се променя по време на изпълнение - полетата могат да се добавят или премахват, типовете могат да се променят и т.н. Въпреки че това е възможно с помощта на отражение в C #, отражението представлява „тъмните изкуства“ на този език и разработчиците очакват да наруши функционалността.
Този проблем ми беше представен по време на работа преди няколко години, когато работех в основния екип на ApeeScape. Изграждахме пъргаво табло за управление на нашите отбори, което трябваше да бъде бързо; в противен случай разработчиците и собствениците на продукти не биха го използвали. Извличахме данни от редица източници: нашата система за проследяване на работата, нашият инструмент за управление на проекти и база данни. Сайтът е изграден в Node.js / Express и имаме кеш памет, за да сведем до минимум обажданията към тези източници на данни. Нашият бърз, итеративен процес на разработка означаваше, че ние разполагахме (и следователно рестартирахме) няколко пъти на ден, като обезсилвахме кеша и по този начин загубихме много от предимствата му.
Очевидно решение беше кеш паметта извън процеса като Редис . След някои изследвания обаче установих, че не съществува добра библиотека за сериализация за JavaScript. Вградените методи JSON.stringify / JSON.parse връщат данни от типа обект, като губят всякакви функции върху прототипите на оригиналните класове. Това означаваше, че десериализираните обекти не могат просто да бъдат използвани „на място“ в нашето приложение, което следователно ще изисква значително рефакторинг, за да работи с алтернативен дизайн.
на какъв език са програмирани роботите
За да подпомогнем сериализацията и десериализацията на произволни данни в JavaScript, с десериализираните представяния и оригинали, използваеми като взаимозаменяеми, ни трябваше библиотека за сериализация със следните свойства:
За да запълня тази празнина, реших да напиша Tanagra.js , библиотека за сериализация с общо предназначение за JavaScript. Името на библиотеката е препратка към един от любимите ми епизоди на Стар Трек: Следващото поколение , където екипажът на Предприятие трябва да се научи да общува с мистериозна извънземна раса, чийто език е неразбираем. Тази библиотека за сериализация поддържа общи формати за данни, за да се избегнат подобни проблеми.
Tanagra.js е проектиран да бъде опростен и лек и понастоящем поддържа Node.js (не е тестван в браузър, но на теория би трябвало да работи) и класове ES6 (включително Maps). Основната реализация поддържа JSON, а експерименталната версия поддържа буфери на Google Protocol. Библиотеката изисква само стандартен JavaScript (понастоящем тестван с ES6 и Node.js), без зависимост от експериментални функции, Бабел транспилиране, или TypeScript .
Сериализуемите класове се маркират като такива с извикване на метод, когато класът се експортира:
module.exports = serializable(Foo, myUniqueSerialisationKey)
Методът връща a пълномощник към класа, който прихваща конструктора и инжектира уникален идентификатор. (Ако не е посочено, това по подразбиране е името на класа.) Този ключ е сериализиран с останалите данни и класът също го излага като статично поле. Ако класът съдържа някакви вложени типове (т.е. членове с типове, които се нуждаят от сериализиране), те също са посочени в извикването на метод:
module.exports = serializable(Foo, [Bar, Baz], myUniqueSerialisationKey)
(Вложените типове за предишни версии на класа също могат да бъдат посочени по подобен начин, така че, например, ако сериализирате Foo1, той може да бъде десериализиран във Foo2.)
как да заобиколите проверката на възрастта с кредитна карта
По време на сериализацията библиотеката рекурсивно изгражда глобална карта на ключовете към класовете и използва това по време на десериализацията. (Не забравяйте, че ключът е сериализиран с останалите данни.) За да се знае типа на класа „най-високо ниво“, библиотеката изисква това да бъде посочено в извикването за десериализация:
const foo = decodeEntity(serializedFoo, Foo)
Експериментална библиотека за автоматично картографиране обикаля дървото на модула и генерира съпоставянията от имената на класове, но това работи само за класове с уникално име.
Проектът е разделен на няколко модула:
как да стартирате частен фонд за недвижими имоти
Имайте предвид, че библиотеката използва правопис в САЩ.
Следващият пример декларира сериализуем клас и използва модула tanagra-json, за да го сериализира / десериализира:
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)
Сравних производителността на двата сериализатора ( JSON сериализатор и експериментален protobufs сериализатор) с контрола (роден JSON.parse и JSON.stringify). Проведох общо 10 опита с всеки.
Тествах това на моята 2017 година Dell XPS15 лаптоп с 32Gb памет, работещ с Ubuntu 17.10.
Сериализирах следния вложен обект:
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 } } }, }
Метод на сериализиране | Ave. inc. първо изпитание (ms) | StDev. вкл. първо изпитание (ms) | Пр. Напр. първо изпитание (ms) | StDev. напр. първо изпитание (ms) |
JSON | 0,115 | 0,0903 | 0,0879 | 0,0256 |
Google Protobufs | 2.00 | 2,748 | 1.13 | 0,278 |
Контролна група | 0,0155 | 0,00726 | 0,0139 | 0,00570 |
Прочети
node js връща стойност от функцията
Метод на сериализиране | Ave. inc. първо изпитание (ms) | StDev. вкл. първо изпитание (ms) | Пр. Напр. първо изпитание (ms) | StDev. напр. първо изпитание (ms) |
JSON | 0,133 | 0.102 | 0.104 | 0,0429 |
Google Protobufs | 2.62 | 1.12 | 2.28 | 0,364 |
Контролна група | 0,0135 | 0,00729 | 0,0115 | 0,00390 |
The JSON сериализаторът е около 6-7 пъти по-бавен от родната сериализация. Експерименталният protobufs сериализаторът е около 13 пъти по-бавен от JSON сериализатор или 100 пъти по-бавно от естествената сериализация.
Освен това, вътрешното кеширане на схема / структурна информация във всеки сериализатор очевидно има ефект върху производителността. За сериализатора JSON първото записване е около четири пъти по-бавно от средното. За сериализатора protobuf е девет пъти по-бавен. Така че писането на обекти, чиито метаданни вече са кеширани, е много по-бързо във всяка една библиотека.
Същият ефект се наблюдава и при четене. За библиотеката JSON първото четене е около четири пъти по-бавно от средното, а за библиотеката protobuf е около два пъти и половина по-бавно.
Проблемите с производителността на сериализатора protobuf означават, че той все още е в експериментален етап и бих го препоръчал само ако имате нужда от формата по някаква причина. Струва си обаче да инвестирате известно време, тъй като форматът е много по-строг от JSON и следователно е по-добър за изпращане по кабела. Stack Exchange използва формата за своето вътрешно кеширане.
JSON сериализаторът очевидно е много по-ефективен, но все пак значително по-бавен от родната реализация. За малки обектни дървета тази разлика не е значителна (няколко милисекунди на върха на заявка от 50 ms няма да унищожат ефективността на вашия сайт), но това може да се превърне в проблем за изключително големи дървета на обекти и е един от приоритетите ми за развитие.
Библиотеката все още е в бета фаза. JSON сериализаторът е сравнително добре тестван и стабилен. Ето пътната карта за следващите няколко месеца:
Не знам за друга библиотека на JavaScript, която да поддържа сериализиране на сложни, вложени обектни данни и десериализиране до първоначалния си тип. Ако внедрявате функционалност, която би се възползвала от библиотеката, моля, опитайте, свържете се с отзивите си и помислете за принос.
как да кодирам c++
Начална страница на проекта
Хранилище на GitHub
Като цяло обектите не се съхраняват. Те се инстанцират, когато е необходимо, използват се при обработка, след което се премахват от паметта, когато вече не са необходими. Ако трябва да използваме временно данни на друго място, ние сериализираме и десериализираме тези данни в друга структура.
Обектът е парче код, което капсулира структура, заедно с операции, които могат да бъдат изпълнени върху тази структура. Като цяло той е същият като обект във всеки обектно-ориентиран език за програмиране.
Обектът от данни е код, който временно съдържа данни от хранилище за данни, така че да може да бъде прочетен или обработен в приложение. Освен ако няма начин тези данни да се запазят в паметта, те се записват обратно или по друг начин не се задържат, когато обектът излезе извън обхвата или по друг начин не е необходим.
Сериализацията ни позволява да съхраняваме данни за използване в текущия процес или други процеси, ако е необходимо. Съхраняваме данните, след което десериализираме, когато се използват другаде.