JS Typed Arrays, Buffers & Atomics
Direct binary memory management in JavaScript: allocate continuous memory with ArrayBuffer, slice views with TypedArrays & DataView, and synchronize thread memory with SharedArrayBuffer and Atomics.
ArrayBuffer Memory Layout & Typed Array Views
An ArrayBuffer represents a raw chunk of contiguous bytes in physical memory. It has no format until viewed through a TypedArray or DataView lens.
1. The TypedArray Ecosystem & Clamping
Standard JavaScript arrays are dynamic hash maps in memory that can grow, shrink, and hold mixed data types. In high-performance domains (WebGL 3D graphics, audio synthesis, cryptography, WebAssembly), this causes memory fragmentation. TypedArrays provide C-speed continuous binary arrays.
| TypedArray Type | Bytes/Element | Value Range | Use Case |
|---|---|---|---|
Uint8Array |
1 | 0 to 255 | Binary streams, network packets, file I/O |
Uint8ClampedArray |
1 | 0 to 255 (Clamped, no rollover!) | HTML5 Canvas 2D ImageData (RGBA pixels) |
Int16Array / Uint16Array |
2 | -32,768 to 32,767 / 0 to 65,535 | WAV audio samples, UTF-16 character codes |
Float32Array |
4 | IEEE-754 32-bit single float | WebGL 3D vertex coordinates, shaders |
Float64Array |
8 | IEEE-754 64-bit double float | Physics engines, mathematical simulations |
BigInt64Array |
8 | 64-bit signed integer | High-resolution microsecond timestamps |
Clamping vs Rollover: The Canvas Secret
Standard Uint8Array overflows via modular arithmetic, while Uint8ClampedArray clamps cleanly to 0 or 255:
const normal = new Uint8Array(1);
const clamped = new Uint8ClampedArray(1);
normal[0] = 300; // ❌ Rollover! 300 % 256 = 44
clamped[0] = 300; // ✅ Clamped to maximum 255 (vital for image color saturation!)
normal[0] = -10; // ❌ Underflow! Wraps to 246
clamped[0] = -10; // ✅ Clamped to minimum 0
Run in Playground
2. DataView & Endianness Control
TypedArrays assume the host computer's native byte order (almost always Little-Endian on modern x86/ARM processors). When parsing network protocol packets or binary media files (like PNG, WAV, or MP4), byte formats frequently specify Big-Endian order. DataView gives you absolute control over offsets and endianness.
Reading Big-Endian vs Little-Endian with DataView
const buffer = new ArrayBuffer(4);
const view = new DataView(buffer);
// Write 16-bit integer at byte offset 0 in Big-Endian:
view.setUint16(0, 0x1234, false); // false = Big-Endian
// Read back in Little-Endian:
const valLE = view.getUint16(0, true); // true = Little-Endian
console.log(valLE.toString(16)); // '3412' (Bytes reversed!)
Test in Playground
3. Multi-Threading with SharedArrayBuffer & Atomics
Standard Web Workers communicate via message copying (postMessage). SharedArrayBuffer allows multiple Web Workers to share the exact same physical memory block simultaneously. To prevent race conditions where two threads overwrite each other, the Atomics namespace provides uninterrupted atomic memory operations:
Atomics.add(typedArray, index, val)Increments the value at the specified index atomically. Guaranteed never to interleave with another thread's read or write.
Atomics.wait() / Atomics.notify()Implements thread sleep and wakeup synchronization primitives directly in Web Workers without spinning the CPU.
Interactive Lab: Raw Binary Buffer Inspector
Live Memory Inspector
Below is an 8-byte ArrayBuffer. Type a number to write into index 0 as a Uint8Array vs Uint8ClampedArray and observe the hexadecimal byte layout.
Build a Binary WAV Audio Header Parser with DataView
Implement a parseWavHeader(arrayBuffer) function using DataView. Extract the sample rate (32-bit integer at byte offset 24, Little-Endian) and number of audio channels (16-bit integer at byte offset 22, Little-Endian).
function parseWavHeader(buffer) {
if (buffer.byteLength < 44) {
throw new Error('Invalid WAV header: Buffer too small');
}
const view = new DataView(buffer);
// Read ASCII RIFF chunk identifier
const riff = String.fromCharCode(
view.getUint8(0), view.getUint8(1), view.getUint8(2), view.getUint8(3)
);
if (riff !== 'RIFF') {
throw new Error('Not a valid RIFF file');
}
// Audio Channels: 16-bit int at offset 22 (Little-Endian)
const channels = view.getUint16(22, true);
// Sample Rate (e.g. 44100Hz): 32-bit int at offset 24 (Little-Endian)
const sampleRate = view.getUint32(24, true);
// Bits per sample (e.g. 16-bit): 16-bit int at offset 34 (Little-Endian)
const bitsPerSample = view.getUint16(34, true);
return { channels, sampleRate, bitsPerSample };
}
Chapter 35 Knowledge Check
Validate your understanding of ArrayBuffers, TypedArrays, DataView endianness, and Atomics.
ArrayBuffer without creating a View?Uint8ClampedArray?DataView over standard TypedArrays?Atomics required when multiple Web Workers share a SharedArrayBuffer?Float32Array consume in physical memory?