Chapter 1 of ?
js 9 min read

JavaScript Mastery — Chapter 35: JS Typed Arrays, Buffers & Atomics

Module 8: Formats, Modules & Metaprogramming • Chapter 35

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.

ArrayBuffer(16): B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF Uint8Array(16): 16 elements × 1 byte each (0 to 255) Int32Array(4): 4 elements × 4 bytes each (-2,147,483,648 to 2,147,483,647) Float64Array(2): 2 double-precision IEEE-754 floats × 8 bytes each

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.

RAW MEMORY HEAP BYTES (8 Bytes):
Stored Value: 255 (Clamped from 280)
Hands-on Challenge

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.

1. Can you read or write data directly on an ArrayBuffer without creating a View?
Yes, ArrayBuffer has push and pop methods
No, an ArrayBuffer is pure raw memory; you must create a TypedArray or DataView to read or write bytes
Yes, by using bracket notation (buffer[0])
Only in Node.js
2. What happens if you assign the number 300 to index 0 of a Uint8ClampedArray?
It overflows to 44 (300 % 256)
It clamps to the maximum upper bound of 255
It throws a RangeError
It coerces to NaN
3. What is the fundamental advantage of DataView over standard TypedArrays?
It uses 50% less RAM
It allows explicit control over byte offsets and Big-Endian vs Little-Endian byte order
It can store JavaScript functions
It runs on GPU shaders
4. Why is Atomics required when multiple Web Workers share a SharedArrayBuffer?
To compress data over HTTP/2
To prevent race conditions and guarantee that simultaneous memory reads and writes complete without corruption
To decrypt HTTPS certificates
It is required by the CSS engine
5. How many bytes does an element in a Float32Array consume in physical memory?
1 byte
2 bytes
4 bytes (32 bits / 8 bits per byte = 4 bytes)
8 bytes
Done with this chapter?
Mark it complete to track your progress and unlock your certificate.
Next Up
—

Learner Reviews

Write a Review
Share your experience to help other learners.
Your Rating *
★ ★ ★ ★ ★