A proposal to transport structured clone and post message complex references.
// either main thread or workers or iframes
import * as SerializationRegistry from '@ungap/serialization-registry';
// THE PROPOSAL
// similar to Symbol.toStringTag, an accessor that returns
// structured or transfered data to represent the instance
SerializationRegistry.symbol;
// register once a reviver that will receive the data
// returned via `ref[SerializationRegistry.symbol]`
// when deserialization happens
SerializationRegistry.register(
identifier: string,
reviver: (structured:object) => object,
);
// unregister a unique identifier previously registered
SerializationRegistry.unregister(identifier: string);
// an explicit transferable representation of the
// registered entity that will pass through the reviver
// once the other side of the algorithm receive the data
SerializationRegistry.transfer(
identifier: string,
structured: object,
);These two helpers are needed until the proposal lands.
// currently needed to explicit perform recursive-capable
// search of data that should be serialized differently
SerializationRegistry.serialize(data:any);
// currently needed to explicit perform recursive-capable
// search of data that should be deserialized differently
SerializationRegistry.deserialized(data:any);import * as SerializationRegistry from '@ungap/serialization-registry';
const uid = 'my-project@Serializable';
// a serializable class
export class Serializable {
constructor(data) {
this.data = data;
}
get [SerializationRegistry.symbol]() {
return SerializationRegistry.transfer(uid, this.data);
}
}
SerializationRegistry.register(uid, data => new Serializable(data));
// postMessage(new Serializable(123))
// will result into a Serializable instance
export class Structured {
constructor(data) {
this.data = data;
}
get [SerializationRegistry.symbol]() {
return { just: 'some data', without: 'Class' };
}
}
// postMessage(new Structured)
// will result into whathever was returned
// via SerializationRegistry.symbolIf you don't want to remember when/how to use serialize and deserialize you can import the polyfill which will automatically expose SerializationRegistry globally and it will patch, in the least possible obtrusive way, all communication channels that use postMessage, onmessage accessor and addEventListener('message', ...rest) ability.
import '@ungap/serialization-registry/polyfill';
// all utilities (except serialize/deserialize)
// will be available as global namespace
console.log(SerializationRegistry);
// symbol, register, unregister, transferTo keep it fast and simple the recursion happens only to simple references such as arrays and objects.
This means that Map or Set or any other clonable reference won't be crawled internally.
However, if you extend any of those classes and implement SerializationRegistry.symbol getter in their protototype, this will still be reached while serializing so that in there it's possible to eventually crawl internally data and discover serializable field.
If natively implemented this limitation won't exsist because all data will be reached to verify it's specially serializable or not.