ES17 Interactive Hub — ECMAScript 2026
Explicit Resource Management (using/await using with Symbol.dispose), cross-realm-safe Error.isError(), inline RegExp pattern modifiers (?i:...) scope flags, Iterator.range/zip — better ergonomics + safer resource management.
Explicit Resource Management (using)
Core topic
💡 Concept summary
The `using` and `await using` keywords automatically clean up resources when leaving scope via Symbol.dispose / Symbol.asyncDispose — like Python's "with" and C#'s "using".
🤔 Why do you need this feature?
The resource cleanup pattern (closing a file, releasing a lock, closing a DB connection, aborting a fetch) previously required try/finally — verbose, easy to forget, and chaotic with multiple resources. ES17 introduces the `using x = ...` syntax so the JS engine automatically calls x[Symbol.dispose]() when leaving the block, even on throw. `await using` is for async cleanup.
// Before ES17 — manual try/finally, nested when there are many resources
function readFiles() {
const file1 = openFile('a.txt');
try {
const file2 = openFile('b.txt');
try {
const file3 = openFile('c.txt');
try {
return processAll(file1, file2, file3);
} finally {
file3.close();
}
} finally {
file2.close();
}
} finally {
file1.close();
}
}
// The pattern is even worse with async (you need to await inside finally)
async function readAsync() {
const conn = await openDB();
try {
const tx = await conn.beginTransaction();
try {
return await tx.query('...');
} finally {
await tx.rollback();
}
} finally {
await conn.close();
}
}// ES17 — using automatically calls dispose when leaving scope
function createResource(name) {
return {
name,
[Symbol.dispose]() {
console.log(`Closing ${name}`);
}
};
}
function readFiles() {
using file1 = createResource('a.txt');
using file2 = createResource('b.txt');
using file3 = createResource('c.txt');
return process(file1, file2, file3);
// → automatically calls dispose in reverse order: file3, file2, file1
// → even on throw, dispose still runs
}
// async version with Symbol.asyncDispose
function createAsyncResource(name) {
return {
name,
async [Symbol.asyncDispose]() {
await new Promise(r => setTimeout(r, 10));
console.log(`Async closed ${name}`);
}
};
}
async function readAsync() {
await using conn = createAsyncResource('DB');
await using tx = createAsyncResource('TX');
// ... use them
// → await dispose in LIFO order when leaving the async function
}ES17 Quick Reference
Quick syntax overview + copy snippets
The `using` and `await using` keywords automatically clean up resources when leaving scope via Symbol.dispose / Symbol.asyncDispose — like Python's "with" and C#'s "using".
function createResource(name) {
return {
name,
...A static method that robustly checks whether a value is an Error instance — it works across realms (iframe, worker, structuredClone), which `instanceof Error` cannot handle.
console.log(Error.isError(new Error("ok"))); // true
console.log(Error.isError(new TypeError("ok"))); // true
console.log(Error.isError(new RangeError("ok"))); // true
...The `(?i:abc)` and `(?-i:abc)` syntax turns flags (i, m, s) on/off only within part of a regex instead of the whole thing — reducing complexity when writing a regex that combines multiple case sensitivities.
const pattern = /[A-Z]+(?i:end)/;
console.log(pattern.test("HELLOend")); // true
console.log(pattern.test("HELLOEND")); // true
...Two built-in static methods for creating iterators: range(start, end, step) generates a range of numbers, zip(...iters) joins multiple iterators in parallel — no need for Array.from or manual loops.
for (const i of Iterator.range(1, 6)) {
console.log(i); // 1, 2, 3, 4, 5
}
...