> A lightweight, high-performance Ring Buffer for streaming data using JavaScript `TypedArray`s.
npm install ringbud> A lightweight, high-performance Ring Buffer for streaming data using JavaScript TypedArrays.
- ๐ง Frame-based buffering (configurable frame size)
- โก Zero dependencies
- ๐งต Supports all major TypedArrays (e.g. Float32Array, Uint8Array, etc.)
- ๐ฆ Memory efficient with optional frame trimming
- ๐ Sync & async iteration support
- โ
Fully tested and predictable behavior
- ๐งฐ Customizable preallocation and cache options
---
``bash`
npm install ringbud
---
`ts
import { RingBufferU8 } from "ringbud";
// Create a ring buffer with frame size of 100
const rb = new RingBufferU8(100);
// Write 50 bytes (not enough for a full frame)
rb.write(new Uint8Array(50).fill(1));
console.log(rb.empty()); // true
// Write 50 more bytes (now we have a complete frame)
rb.write(new Uint8Array(50).fill(1));
console.log(rb.empty()); // false
// Read one frame of 100 bytes
const frame = rb.read();
console.log(frame); // Uint8Array(100)
// After reading, it becomes empty again
console.log(rb.empty()); // true
`
---
You can instantiate ring buffers for:
- Uint8Array โ RingBufferU8Uint16Array
- โ RingBufferU16Float32Array
- โ RingBufferF32
Each subclass wraps the base RingBufferBase with preconfigured types.
---
All constructors accept:
`ts`
{
frameSize: number, // Number of elements per frame (required)
preallocateFrameCount?: number, // Default: 10
frameCacheSize?: number // Default: 0 (no trim)
}
When frameCacheSize > 0, the ring buffer trims memory usage by shifting unread bytes after every .read(). This reduces buffer growth at the cost of additional memory copying.
---
`ts`
new RingBufferU8(frameSize: number, options?: {
preallocateFrameCount?: number;
frameCacheSize?: number;
});
| Method | Description |
|---------------------|-------------|
| write(data) | Appends a TypedArray to the buffer |read()
| | Returns the next full frame, or null |drain()
| | Returns remaining incomplete data |peek()
| | Returns the entire buffer content (not a copy) |empty()
| | true if no full frame is available |remainingFrames()
| | Number of full frames available to read |rewind()
| | Resets read offset so frames can be re-read |Symbol.iterator()
| | Enables for (const frame of buffer) |Symbol.asyncIterator()
| | Enables for await (const frame of buffer) |
---
`ts
for (const frame of rb) {
console.log(frame); // each is a complete frame
}
// or async
for await (const frame of rb) {
await process(frame);
}
`
---
`ts
const rb = new RingBufferU8(100, { frameCacheSize: 1 });
rb.write(new Uint8Array(300)); // 3 frames
rb.read(); // returns 1st frame
// Buffer automatically shifts remaining frames to the front
rb.peek().subarray(0, 200); // contains frame 2 and 3
`
---
- frameSize must be an integer โฅ 1preallocateFrameCount
- must be โฅ 1 (if set).read()
- Partial frames are never returned from or iteratorsframeCacheSize > 0
- Trimming only occurs after reads when .read()
- If iteration is used, all frames are consumed as if was called repeatedly
- Frames can be shared or copied depending on cache config
---
Internally, the base class accepts any TypedArray constructor:
`ts`
new RingBufferBase({
frameSize: 256,
TypedArrayConstructor: Uint16Array
});
Built-in classes like RingBufferF32 are wrappers over this API.
---
`ts
const rb = new RingBufferU8(100);
rb.write(new Uint8Array(230));
rb.read(); // reads 1 frame (100 bytes)
rb.read(); // reads 1 more frame (100 bytes)
rb.read(); // null (30 bytes left)
rb.drain(); // returns 30 bytes
`
`ts``
rb.rewind(); // enables re-reading all written frames
for (const frame of rb) {
console.log(frame);
}
---