Сериализация и десериализация

Общие сведения

Сериализация и десериализация платформенных типов используется в следующих сценариях: Клонирование экземпляров классов, подмешивающих миксин Types/_entity/CloneableMixin. Сохранение серверного состояния изоморфного приложения на сервере, передача его на клиент и восстановление состояния приложения на клиенте.

В обоих случаях используется платформенный класс Core/Serializer, который предоставляет реализации функций replacer и reviver стандартного для JavaScript механизама сворачивания значения в строку и разворачивания значения из строки. Данный класс поддерживает сериализацию/десериализацию некоторых стандартных типов (например, undefined, Infinty, -Infinity), которые не поддержиаются нативно. Также он поддерживает типы, наследующие либо подмешивающие класс Types/_entity/SerializableMixin.

Пример использования Core/Serializer

import Serializer from 'Core/Serializer';
import {Record, DateTime} from 'Types/entity';

// Определим состояние приложения
const applicationState = {
    resource: 'https://github.com/',
    lastVisit: new DateTime(),
    account: new Record({
        rawData: {
            login: 'root',
            password: '12345'
        }
    })
};

const applicationSerializer = new Serializer();

// Сохраним состояние приложения в строку
const applicationStateString = JSON.stringify(applicationState, applicationSerializer.serialize);

// Восстановим состояние приложения из строки
const applicationStateClone = JSON.parse(applicationStateString, applicationSerializer.deserialize);

// 'root'
console.log(applicationStateClone.account.get('login'));

Особенности реализации

Для восстановления конструкторов значений, сериализованных через Types/_entity/SerializableMixin, в состояние значения сохраняется название модуля, которое при десериализации передается в библиотеку RequireJS для получения конструктора класса. Чтобы этот сценарий работал, нужно соблюдать два условия: 1. При сериализации в классе должно быть задано свойство _moduleName, значение которого записывается в сериализованное состояние. 2. При десериализации модуль с именем, указанным в _moduleName, должен быть загружен через RequireJS до момента вызова JSON.parse().

При нарушении любого из условий будет выброшено соответствующее исключение.

Учитывайте это при работе в изоморфном приложении: если экземпляры вашего класса попадают в сериализованное состояние приложения на сервере, то их конструкторы должны быть доступны для загрузки через библиотеку RequireJS на клиенте.

Платформенный код отслеживает загрузку модулей через RequireJS и по возможности пытается самостоятельно прописать свойство _moduleName в прототипы классов. Но для вашей уверенности мы рекомендуем задавать значение этого свойства в ваших классах явно:

import {Model} from 'Types/entity';
 
class MyModel extends Model {
    protected _moduleName: string = 'MyModule/MyModel';
    // ...
}

Учитывайте все вышесказанное при работе с библиотеками. Если ваш модуль входит в библиотеку и участвует в выполнении серверной части приложения, то он обязательно должен быть экспортирован из библиотеки. В противном случае при десериализации на клиенте вы получите исключение. Самый распространенный тип, который участвует в этих сценариях — это прикладные модели данных — наследники Types/entity:Model.

Вы можете использовать библиотечный синтаксис именования модулей:

import {Model} from 'Types/entity';
 
class MyModel extends Model {
    protected _moduleName: string = 'MyModule/library:MyModel';
    // ...
}