Zum Inhalt springen
Deutsch

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 }
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.

PayloadJSONCBORErsparnis
{ kind: 'increment' }14 Bytes9 Bytes36 %
Order mit 5 Items250 Bytes180 Bytes28 %
Bild-Bytes (10 KB)13,3 KB (base64)10 KB (nativ)25 %
Tief verschachteltes Objektvariiertvariierttypisch 20–40 %

Größere Ersparnisse bei Binärdaten (kein base64-Overhead) und wiederholten Feldnamen (CBOR kann auf Protokollebene string-tabellen).

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:

TypJsonSerializerCborSerializer
Uint8Arraybase64-String (+33 %)native Byte-Kette
ZahlenDezimaltextkompaktes binäres Int / Float
Date{"__date__":"…"}-Tag-ObjektTag 1 + Epoch (kompakt)
bigint{"__bigint__":"…"}-Tag-ObjektBignum-Tag 2 / 3 (kompakt)
Map{"__map__":[…]}-Tag-ObjektTag 259 + native CBOR-Map
Set{"__set__":[…]}-Tag-ObjektTag 258 + Array
URL{"__url__":"…"}-Tag-ObjektTag 32 + Text
Typed Arraysbase64-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. CborSerializer trägt es nativ (CBOR Simple Value 23), { a: undefined } kommt also mit vorhandenem a und dem Wert undefined zurück. JsonSerializer lehnt undefined rundheraus ab — CBOR ist hier also der großzügigere der beiden.
  • Binärdaten außer Uint8Array sind 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.
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-Default
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.

CBOR ist ein binäres getaggtes Format. Rohe Bytes zu inspizieren erfordert ein CBOR-fähiges Tool:

Terminal-Fenster
$ cat events.cbor | cbor-diag
# in diagnostische Notation dekodiert

Zum Debuggen willst du eventuell kurz auf JSON umschalten, um einen Bug zu jagen, und dann wieder zurück.

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.