ECMAScript 2024 (ES15) introduces several long-anticipated features to JavaScript. This article covers the new capabilities with practical examples and guidance on adoption timelines.
Array Grouping: Object.groupBy and Map.groupBy
One of the most requested JavaScript features has finally arrived. Object.groupBy and Map.groupBy partition array elements into groups based on a callback:
const inventory = [
{ name: "asparagus", type: "vegetables", quantity: 5 },
{ name: "bananas", type: "fruit", quantity: 0 },
{ name: "goat", type: "meat", quantity: 23 },
];
const byType = Object.groupBy(inventory, ({ type }) => type);
// { vegetables: [{ name: "asparagus", ... }],
// fruit: [{ name: "bananas", ... }],
// meat: [{ name: "goat", ... }] }
Map.groupBy preserves non-string keys, making it ideal for grouping by objects or symbols. This eliminates the need for external libraries or manual reduce patterns.
Promise.withResolvers
Promise.withResolvers() returns a promise along with its resolve and reject functions as properties, eliminating the need to declare variables outside the constructor:
const { promise, resolve, reject } = Promise.withResolvers();
// Outside the constructor scope
setTimeout(() => resolve("done"), 1000);
await promise; // "done"
This pattern simplifies converting callback-based APIs to promises, managing promise lifecycle in event handlers, and implementing custom async primitives.
ArrayBuffer.prototype.transfer
The transfer and transferToFixedLength methods enable zero-copy ownership transfer between buffers:
const buffer = new ArrayBuffer(1024);
const view = new Uint8Array(buffer);
view[0] = 42;
const transferred = buffer.transfer();
// buffer.byteLength === 0 (detached)
// transferred.byteLength === 1024
This performance-critical feature benefits WebAssembly runtimes, Web Worker communication, and buffer pool management by eliminating memory copies and reducing GC pressure.
String: isWellFormed and toWellFormed
These methods address Unicode well-formedness. Malformed strings containing lone surrogates can cause security vulnerabilities and rendering issues:
const str = "ab\uD800c";
str.isWellFormed(); // false
str.toWellFormed(); // "ab\ufffdc"
const clean = "hello";
clean.isWellFormed(); // true
Essential for user-generated content, internationalization pipelines, and any system processing untrusted text input.
Atomics.waitAsync
Building on the synchronous (and blocking) Atomics.wait, Atomics.waitAsync provides a non-blocking API for shared memory synchronization:
const sab = new SharedArrayBuffer(4);
const int32 = new Int32Array(sab);
Atomics.store(int32, 0, 0);
const { async, value } = Atomics.waitAsync(int32, 0, 0);
// { async: true, value: Promise<"ok" | "not-equal" | "timed-out"> }
This enables lock-free data structures, efficient cross-thread synchronization, and real-time data processing without blocking the main thread.
Adoption Timeline
| Timeframe | Availability |
|---|---|
| 0-6 months | Chrome, Firefox Nightly, Node.js (–harmony) |
| 6-12 months | Stable in major browsers, Node.js LTS |
| 12-18 months | Polyfills available, early production adoption |
| 18-24 months | Widespread use, TypeScript support, ESLint rules |
Other Notable Additions
ES2024 also includes the RegExp.prototype.unicodeSets flag (v flag) for improved character class operations, resizable ArrayBuffer support, and standardized error cause chains via the cause property on Error.
Conclusion
ES2024 delivers practical improvements that address daily developer needs. Array grouping simplifies data transformation, Promise.withResolvers cleans up async patterns, and ArrayBuffer transfer unlocks new performance possibilities. Start experimenting today through polyfills and prepare for native support as browsers adopt these features throughout the year.
