bobj
v2.0.0
Published
A modular JavaScript object serialization library.
Readme
Bobj - A modular JavaScript object serialization library
Introduction
Bobj is short for "Binary Object", and it is a lightweight, extensible JavaScript library designed to serialize JavaScript objects into a binary format (bobj) and deserialize bobj binary data back into JavaScript objects. It supports built-in data types (objects, arrays, Uint8Array, strings, numbers, booleans, null, and undefined) and provides a plugin system for custom data type handling.
Key Features
- Multi-type Support: Serializes/deserializes common JavaScript primitives and objects.
- Extensible Plugin System: Add support for custom data types via plugins.
- Binary Format: Efficient binary representation for compact storage/transmission.
Installation
# Using pnpm
pnpm install bobj
# Using npm
npm install bobjBasic Usage
Serialization (Object → bobj Binary)
import { Serializer } from "bobj";
// Define an object to serialize
const exampleObj = {
name: "Bobj",
version: 1.0,
tags: ["serialization", "binary"],
active: true,
metadata: new Uint8Array([0x01, 0x02, 0x03]),
nesting:{
name: "Bobj",
version: 1.0,
tags: ["serialization", "binary"],
active: true,
metadata: new Uint8Array([0x01, 0x02, 0x03]),
}
};
// Create a serializer instance
const serializer = new Serializer();
// Serialize the object to a Uint8Array (bobj format)
const bobjBinary = await serializer.serialize(exampleObj);
// Output: Uint8Array([...binary data...])Deserialization (bobj Binary → Object)
import { Deserializer } from "bobj";
// Create a deserializer instance
const deserializer = new Deserializer();
// Deserialize the bobj binary back to an object
const restoredObj = await deserializer.deserialize(bobjBinary);
// Output: { name: "Bobj", version: 1.0, tags: ["serialization", "binary"], ... }Plugin Example: Custom Data Type Support
Bobj’s plugin system allows you to extend serialization/deserialization for custom data types (e.g., Date, Set, or user-defined classes). Below is an example for handling Date objects.
Step 1: Create a Serialization Plugin
Add a plugin to serialize Date objects into timestamps (stored as 8-byte floats).
// date-serializer-plugin.ts
import type { SerializerPluginType } from "../types/serializer";
import { numberToU8i } from "../utils/number_u8i_converter";
const DateSerializerPlugin: SerializerPluginType<Date> = {
// Filter: Check if the target is a Date
filter: (target) => target instanceof Date,
// Unique type identifier
targetType: new TextEncoder().encode("Date"),
// Serialize Date to a timestamp (8-byte float)
serialize: ({ target }) => {
const timestamp = target.getTime();
return numberToU8i(timestamp); // Convert number to Uint8Array
},
};
export default DateSerializerPlugin;Step 2: Create a Deserialization Plugin
Add a plugin to deserialize 8-byte floats back into Date objects.
// date-deserializer-plugin.ts
import type { DeserializerPluginType } from "../types/deserializer";
import { u8iToNumber } from "../utils/number_u8i_converter";
const DateDeserializerPlugin: DeserializerPluginType<Date> = {
// Filter: Check if the value type is "Date"
filter: new TextEncoder().encode("Date"),
// Deserialize Uint8Array to Date
deserialize: ({ targetArray }) => {
const timestamp = u8iToNumber(targetArray); // Convert Uint8Array to number
return new Date(timestamp);
},
};
export default DateDeserializerPlugin;Step 3: Register Plugins
Register the plugins with the Serializer and Deserializer to enable custom handling.
import { Serializer, Deserializer } from "bobj";
import DateSerializerPlugin from "./date-serializer-plugin";
import DateDeserializerPlugin from "./date-deserializer-plugin";
// Initialize serializer with the Date plugin
const serializer = new Serializer();
serializer.registerPlugin(DateSerializerPlugin);
// Initialize deserializer with the Date plugin
const deserializer = new Deserializer();
deserializer.registerPlugin(DateDeserializerPlugin);
// Test with a Date object
const testDate = {date: new Date("2024-01-01")};
const dateBinary = await serializer.serialize(testDate); // Uint8Array([...timestamp bytes...])
const restoredDate = await deserializer.deserialize(dateBinary); // { date: Date("2024-01-01") }Benchmark Comparison
The benchmark code is generated by AI
All tests were run 1000 times per case on bun, measuring average serialization/deserialization time (ms) and resulting data size (bytes).
For large Uint8Array objects, JSON and BSON are skipped due to their limitations.
| Case | Method | Serialize (ms) | Deserialize (ms) | Data Size (bytes) | |--------------------------------------------------|----------------------|----------------|------------------|-------------------| | Normal Object | bobj | 0.0240 | 0.0168 | 125 | | | bobj (sync) | 0.0152 | 0.0154 | 125 | | | bobj (fastU8iArr) | N/A | 0.0121 | N/A | | | JSON | 0.0011 | 0.0004 | 73 | | | BSON | 0.0044 | 0.0038 | 93 | | | msgpack | 0.0045 | 0.0030 | 46 | | Object with 1000 keys | bobj | 1.6406 | 1.1971 | 15890 | | | bobj (sync) | 1.6498 | 1.2041 | 15890 | | | bobj (fastU8iArr) | N/A | 1.2003 | N/A | | | JSON | 0.1188 | 0.0569 | 9781 | | | BSON | 0.1886 | 0.1586 | 8895 | | | msgpack | 0.1623 | 0.1867 | 6509 | | Large Uint8Array (10MB) | bobj | 1.7151 | 1.4187 | 10,485,771 | | | bobj (sync) | 1.6250 | 1.4469 | 10,485,771 | | | bobj (fastU8iArr) | N/A | 0.0012 | N/A | | | JSON | N/A | N/A | N/A | | | BSON | 2.1513 | 0.0013 | 10,485,776 | | | msgpack | 3.4741 | 1.4098 | 10,485,772 | | Large Uint8Array (100MB) | bobj | 18.8989 | 15.2495 | 104,857,612 | | | bobj (sync) | 17.8462 | 15.1305 | 104,857,612 | | | bobj (fastU8iArr) | N/A | 0.0012 | N/A | | | JSON | N/A | N/A | N/A | | | BSON | N/A | N/A | N/A | | | msgpack | 35.0774 | 15.1874 | 104,857,612 | | Deep Nested (depth=10, string at last level) | bobj | 1.2739 | 0.7761 | 6,972 | | | bobj (sync) | 0.9884 | 0.5930 | 6,972 | | | bobj (fastU8iArr) | N/A | 0.5478 | N/A | | | JSON | 0.3507 | 0.0460 | 6,015 | | | BSON | 0.2978 | 0.0663 | 8,020 | | | msgpack | 0.2612 | 0.2267 | 3,011 | | Deep Nested (depth=10, 10MB at last level) | bobj | 1.5191 | 1.6598 | 10,485,851 | | | bobj (sync) | 1.8928 | 1.5833 | 10,485,851 | | | bobj (fastU8iArr) | N/A | 0.0065 | N/A | | | JSON | N/A | N/A | N/A | | | BSON | 2.1945 | 0.0012 | 10,485,856 | | | msgpack | 3.3996 | 1.4840 | 10,485,802 | | Deep Nested (depth=1000, string at last level)| bobj | 1.0393 | 0.7277 | 6,972 | | | bobj (sync) | 0.9754 | 0.5520 | 6,972 | | | bobj (fastU8iArr) | N/A | 0.5602 | N/A | | | JSON | 0.3607 | 0.0470 | 6,015 | | | BSON | 0.2759 | 0.0417 | 8,020 | | | msgpack | 0.2568 | 0.1952 | 3,011 | | Deep Nested (depth=1000, 10MB at last level) | bobj | 3.3488 | 3.0316 | 10,493,771 | | | bobj (sync) | 3.2013 | 2.8082 | 10,493,771 | | | bobj (fastU8iArr) | N/A | 0.5609 | N/A | | | JSON | N/A | N/A | N/A | | | BSON | N/A | N/A | N/A | | | msgpack | 3.9857 | 1.7409 | 10,488,772 |
Notes:
- "N/A" means the method is not applicable due to format limitations (e.g., JSON cannot handle
Uint8Array, BSON has a 16MB document size limit). - All times are averages over 1000 runs, measured in milliseconds.
- Data size is the serialized byte length.
- The fast version of bobj deserialization uses
import { fastU8iArrDeserializerPlugin } from "bobj", this will accelerate the parsing of Uint8Array type data; however, the parsed data will contain references to the original data. - For deep nested cases, only the deepest level contains the actual data (
Uint8Array), while all upper levels are just nested objects without additional payload. - Implementations used in the benchmark:
- JSON: Bun built-in
JSON.stringifyandJSON.parse - BSON:
bson(BSON.serialize,BSON.deserialize) - msgpack:
msgpack-lite(msgpack.encode,msgpack.decode)
- JSON: Bun built-in
bobj Binary Format Specification
Each element in the bobj binary follows this structure:
| 8 bits | 8 bits | 8 bits | Variable bits | Variable bits | Variable bits | Variable bits | |--------------|--------------|--------------|---------------|---------------|---------------|---------------| | Key length | Value type length | Value length length | Key | Value type | Value length | Value data |
- Key length: Length of the key (in bytes, 0-255).
- Value type length: Length of the value type identifier (e.g., "Number", "Date", in bytes, 0-255).
- Value length length: Length of the value length field (in bytes, 0-255).
- Key: UTF-8 encoded key string.
- Value type: UTF-8 encoded type identifier (e.g., "String", "Array").
- Value length: Binary representation of the value data length (converted via
int2bytes). - Value data: Binary data of the value (e.g., string bytes, number bytes).
License
MIT © MiaoSpring
