slaysocket
v37.0.0
Published
Ultra low-latency zero-copy WebSocket engine
Maintainers
Readme
slaysocket ⚡
Ultra-low latency, zero-copy, zero-allocation, lock-free WebSocket client for Node.js. Built for high-frequency trading (HFT), high-throughput gateways, and real-time streaming pipelines.
npm: https://www.npmjs.com/package/slaysocket node: >= 16.0.0 license: MIT
Why slaysocket?
Standard Node.js WebSocket libraries (such as ws or socket.io) are optimized for general web applications. Under high-frequency message streams (>100k msg/sec), their parsing logic creates heavy garbage collector (GC) pressure through constant buffer allocations, string decoding, and chunk slicing. The result is unpredictable Stop-The-World GC pauses and latency spikes that are unacceptable in latency-sensitive systems.
slaysocket redesigns the client-side network pipeline around bare-metal V8 execution path optimization:
Zero-Copy Hot Path Incoming TCP/TLS frames are parsed and written directly into shared memory boundaries (SharedArrayBuffer). Payloads are surfaced to your application via offset-based subarray views — zero heap allocations per message.
Lock-Free Atomic IPC Uses native JavaScript Atomics for microsecond-level synchronization between the network worker thread and the main application thread, without blocking the event loop.
Branch-Minimized Stream Parser A state-machine parser tuned for V8 Turbofan inline compilation. Skips regex operations, redundant UTF-8 validation, and unnecessary object wrapping.
Architecture Blueprint
+-----------------------------------+
| Worker Thread (TLS/WSS) |
| - Stream Framing / Deframing |
| - Branch-Minimized State Machine |
| - Permessage-Deflate (zlib) |
+-----------------+-----------------+
|
| Direct pointer-offset write
v
+-----------------------------------+
| SharedArrayBuffer Pool |
| [ Ring Buffer Memory Arena ] |
+-----------------+-----------------+
|
| Atomics signaling (lock-free)
v
+-----------------------------------+
| Main Application Thread |
| - Instant .subarray(off, len) |
| - Zero heap allocation / copy |
+-----------------------------------+How it works:
- The worker thread owns the TLS/TCP socket and performs all framing and deframing, writing fully framed payloads into a pre-allocated ring buffer inside a SharedArrayBuffer.
- The ring buffer acts as the sole transport between threads. Its memory is allocated once at startup and never grows — heap usage stays flat regardless of message volume.
- The main thread receives an atomic signal via Atomics.notify, reads the length from the control block, and exposes a Buffer.subarray(off, len) view — no copy, no allocation.
- Because the main thread never performs I/O or parsing, GC pauses in user code cannot interfere with the network pipeline, and vice versa.
Installation
npm install slaysocketRequirements: Node.js >= 16.0.0 (requires native SharedArrayBuffer, Atomics, and worker_threads support).
Quick Start
import SlaySocket from 'slaysocket';
const client = new SlaySocket({
host: 'stream.binance.com',
port: 443,
path: '/ws/btcusdt@trade',
headers: {
'User-Agent': 'SlaySocket-Client'
},
utf8skip: true, // Bypass costly UTF-8 validation on incoming text frames
zlib: false // Disable permessage-deflate for pure throughput
});
// The listener receives a zero-copy Buffer subarray
client.on('message', (payload) => {
console.log(payload.toString());
});
client.on('terminate', () => {
console.warn('Socket connection closed.');
});
// Spawn the worker thread and open the TLS connection
client.start();Configuration
new SlaySocket(options);host Type: string Default: required Destination server hostname (e.g. gateway.discord.gg).
port Type: number Default: 443 Connection port (443 for TLS/WSS, 80 for plain WS).
path Type: string Default: '/' WebSocket endpoint path (query string included).
headers Type: Object Default: {} Custom HTTP headers sent during the handshake.
sabSize Type: number Default: 7340032 (7 MB) Size of the pre-allocated SharedArrayBuffer ring buffer, in bytes.
utf8skip Type: boolean Default: true Skips UTF-8 validation on incoming text frames for lower latency.
zlib Type: boolean Default: false Enables permessage-deflate decompression via node:zlib.
API Reference
.start() Spawns the background network worker thread, performs a TLS 1.3 handshake, and begins listening on the framing socket. Returns: this
.send(data, opcode = 1) Sends a frame over the active connection asynchronously. data - <string | Buffer> payload to send. opcode - 1 for Text, 2 for Binary. Defaults to 1. Returns: this
.ping() Sends an auto-masked ping control frame over the active session. Returns: this
.stop() Gracefully stops the worker thread, destroys open TLS/TCP streams, and releases shared memory locks. Returns: this
Benchmarks
Local ring-buffer benchmark streaming 1,000,000 high-frequency JSON frames. slaysocket sustains significantly higher throughput while keeping memory usage flat.
GC pauses ws (baseline): frequent slaysocket: 0 pauses (zero-alloc)
Heap memory growth ws (baseline): dynamic scaling slaysocket: flat line (pre-allocated)
Throughput (1M messages) ws (baseline): ~210,000 msg/sec slaysocket: >1,150,000 msg/sec
Handling latency ws (baseline): variable (GC spikes) slaysocket: sub-microsecond
Benchmarks measured on Node.js 20 LTS, Linux x86_64, loopback interface. Results vary by hardware and payload shape.
License
Distributed under the MIT License.
