CBOR-Serializer
CborSerializer kodiert Werte mit CBOR (RFC 8949) — einem
kompakten binären Serialisierungsformat. Kompakter als JSON,
schneller für binärlastige Daten, ähnliche API-Oberfläche.
import { CborSerializer } from 'actor-ts';
const serializer = new CborSerializer();const bytes = serializer.toBinary({ kind: 'increment', n: 1 });// → Uint8Array (binäres CBOR, kleiner als JSON)
const decoded = serializer.fromBinary(bytes, '');// → { kind: 'increment', n: 1 }Wann CBOR sinnvoll ist
Abschnitt betitelt „Wann CBOR sinnvoll ist“| Du solltest auf CBOR umstellen, wenn … |
|---|
| Nachrichten Binärdaten tragen (Bilder, kodierte Payloads). |
| Cluster-Bandbreite messbar / abgerechnet ist (Cross-Region, Mobilfunk-IoT). |
| Persistenz-Storage-Kosten mit der Payload-Größe skalieren. |
| Anhaltend Millionen kleiner Nachrichten, bei denen JSON-Parse-Kosten in Profilen auftauchen. |
Für die meisten Apps ist JSON okay — CBORs Vorteile rechtfertigen den Verlust der Menschenlesbarkeit beim Debuggen nicht.
Größenvergleich
Abschnitt betitelt „Größenvergleich“| Payload | JSON | CBOR | Ersparnis |
|---|---|---|---|
{ kind: 'increment' } | 14 Bytes | 9 Bytes | 36 % |
| Order mit 5 Items | 250 Bytes | 180 Bytes | 28 % |
| Bild-Bytes (10 KB) | 13,3 KB (base64) | 10 KB (nativ) | 25 % |
| Tief verschachteltes Objekt | variiert | variiert | typisch 20–40 % |
Größere Ersparnisse bei Binärdaten (kein base64-Overhead) und wiederholten Feldnamen (CBOR kann auf Protokollebene string-tabellen).
Was CBOR besser handhabt als JSON
Abschnitt betitelt „Was CBOR besser handhabt als JSON“Beide Serializer round-trippen dieselben reichen Typen, der Gewinn ist also vor allem die Größe — CBOR kodiert sie als kompaktes Binärformat statt als getaggten JSON-Text:
| Typ | JsonSerializer | CborSerializer |
|---|---|---|
Uint8Array | base64-String (+33 %) | native Byte-Kette |
| Zahlen | Dezimaltext | kompaktes binäres Int / Float |
Date | {"__date__":"…"}-Tag-Objekt | Tag 1 + Epoch (kompakt) |
bigint | {"__bigint__":"…"}-Tag-Objekt | Bignum-Tag 2 / 3 (kompakt) |
Map | {"__map__":[…]}-Tag-Objekt | Tag 259 + native CBOR-Map |
Set | {"__set__":[…]}-Tag-Objekt | Tag 258 + Array |
URL | {"__url__":"…"}-Tag-Objekt | Tag 32 + Text |
| Typed Arrays | base64-String (+33 %) | native Byte-Kette |
„Dieselben reichen Typen” ist wörtlich gemeint: Map, Set,
BidirectionalMap,
BidirectionalMultiMap,
RegExp, URL, Error, jedes Typed Array, NaN / Infinity /
-0 und bigint kommen aus beiden Serializern als echte Instanzen
zurück, und eine gemeinsame Test-Suite stellt sicher, dass die
beiden sich bei jedem einzelnen einig sind.
Das war nicht immer so: CborSerializer hat Map, Set und die
beiden bidirektionalen Collections früher zu einem leeren {}
plattgemacht und dabei jeden Eintrag verloren, ohne dass irgendetwas
gemeldet wurde
(#1036). Wer das
umgangen hat, indem er vor dem Kodieren in Arrays oder Plain-Objekte
konvertiert hat, braucht das nicht mehr.
Zwei Unterschiede bleiben, beide bewusst:
undefined.CborSerializerträgt es nativ (CBOR Simple Value 23),{ a: undefined }kommt also mit vorhandenemaund dem Wertundefinedzurück.JsonSerializerlehntundefinedrundheraus ab — CBOR ist hier also der großzügigere der beiden.- Binärdaten außer
Uint8Arraysind Little-Endian. Typed Arrays reisen als die Bytes ihrer Plattform. Jede von actor-ts unterstützte Runtime ist Little-Endian, das ist also nur relevant, wenn du die Bytes selbst an einen Big-Endian-Peer weitergibst.
CBOR zum Extension-Default machen
Abschnitt betitelt „CBOR zum Extension-Default machen“import { SerializationExtensionId, CborSerializer } from 'actor-ts';
const ext = system.extension(SerializationExtensionId);ext.setDefault(new CborSerializer());Das ändert, welchen Serializer die SerializationExtension als
ihren Default behandelt — den, den ext.encode(value) für jeden
Wert ohne spezifische Klassenbindung nutzt. Es rüstet CBOR
nicht auf den Cluster-Wire oder die Persistenz-Stores um:
Cross-Node-tells gehen weiterhin als JSON.stringify über die
Leitung (siehe die Übersicht), und
Journal- / Durable-State- / Snapshot-Stores schreiben ihr eigenes
JSON. Um CBOR-Bytes für eine bestimmte Payload zu erhalten, nutze
CborSerializer direkt (siehe Serialisierung pro Aufruf unten).
Per-Class-Bindung funktioniert weiterhin — register den
Serializer, dann bind die Klasse an ihre numerische ID:
const eventSerializer = new ProtobufSerializer<MyEvent>();ext.register(eventSerializer);ext.bind(MyEvent, eventSerializer.id);// MyEvent → Protobuf; andere Werte → der Extension-DefaultSerialisierung pro Aufruf
Abschnitt betitelt „Serialisierung pro Aufruf“import { CborSerializer } from 'actor-ts';
const ser = new CborSerializer();const bytes = ser.toBinary({ data: someUint8Array });
// Später:const back = ser.fromBinary(bytes, '') as { data: Uint8Array };Nützlich, wenn du CBOR für einen bestimmten Use-Case willst (z. B. HTTP-Response-Bodies für Binärdaten), ohne den Cluster- Default umzuschalten.
Wire-Format
Abschnitt betitelt „Wire-Format“CBOR ist ein binäres getaggtes Format. Rohe Bytes zu inspizieren erfordert ein CBOR-fähiges Tool:
$ cat events.cbor | cbor-diag# in diagnostische Notation dekodiertZum Debuggen willst du eventuell kurz auf JSON umschalten, um einen Bug zu jagen, und dann wieder zurück.
Library
Abschnitt betitelt „Library“Die CBOR-Implementierung des Frameworks ist intern — pures JS, keine extra Abhängigkeiten. Konform zu RFC 8949.
Für externe Interoperabilität (CBOR an Nicht-actor-ts-Systeme senden) folgt die Kodierung des Frameworks dem Standard — jeder RFC-8949-konforme Decoder liest es.
Wohin als Nächstes
Abschnitt betitelt „Wohin als Nächstes“- Serialization-Übersicht — das große Bild.
- JSON-Serializer — der Default.
- Eigene Serializer — für typisierte Schemas.
- Object-Storage-Kompression — der andere Größen-Reduktionshebel.
