The JavaScript ecosystem moves fast, but certain patterns stabilize and become idioms. These are the ones that have earned their place in production codebases — not because they’re clever, but because they make intent clear and eliminate whole categories of bugs.
Nullish Coalescing and Optional Chaining
These two operators work as a pair and cover the majority of defensive programming needs:
// Remove item by index const withoutFirst = { ...state, posts: state.posts.filter((_, i) => i !== 0), };
// Update item by index const updated = { ...state, posts: state.posts.map((p, i) => i === 1 ? 'B' : p), };
Async Patterns
Parallel vs Sequential
1 2 3 4 5 6 7 8 9 10 11
// SEQUENTIAL — each waits for the previous (slow) const user = awaitgetUser(id); const posts = awaitgetPosts(user.id); const comments = awaitgetComments(user.id);
// PARALLEL — all fire at once (fast when independent) const [user, posts, comments] = awaitPromise.all([ getUser(id), getPosts(id), getComments(id), ]);
Error Handling Without try/catch Everywhere
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// Wrap in a utility that returns [error, result] asyncfunctionattempt(promise) { try { return [null, await promise]; } catch (err) { return [err, null]; } }
// Clean call sites const [err, data] = awaitattempt(fetchPosts()); if (err) { console.error('Failed to fetch posts:', err.message); return; } renderPosts(data);
Timeout Wrapper
1 2 3 4 5 6 7 8
functionwithTimeout(promise, ms) { const timeout = newPromise((_, reject) => setTimeout(() =>reject(newError(`Timed out after ${ms}ms`)), ms) ); returnPromise.race([promise, timeout]); }
const data = awaitwithTimeout(fetch('/api/posts'), 5000);
The Module Pattern (ESM)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// posts.js — explicit public API via named exports constPOSTS_PER_PAGE = 10;
// Bug: all callbacks capture the same `i` (var) for (var i = 0; i < 3; i++) { setTimeout(() =>console.log(i), 100); // prints 3, 3, 3 }
// Fix 1: use let (block-scoped, new binding each iteration) for (let i = 0; i < 3; i++) { setTimeout(() =>console.log(i), 100); // prints 0, 1, 2 }
// Fix 2: use forEach (each callback gets its own scope) [0, 1, 2].forEach(i => { setTimeout(() =>console.log(i), 100); // prints 0, 1, 2 });
Object Reference Traps
1 2 3 4 5 6 7 8 9 10 11 12
// Both variables point to the same array const a = [1, 2, 3]; const b = a; b.push(4); console.log(a); // [1, 2, 3, 4] — mutated!
// Shallow copy const c = [...a]; const d = Object.assign({}, { x: 1 });
// Deep copy (ES2022+) const e = structuredClone(a);
When Not to Use a Pattern
Patterns have costs — cognitive overhead, indirection, and abstraction layers. The right question is not “can I use this pattern here?” but “does this pattern solve a real problem I have right now?”
Write the simplest code that works. Reach for patterns when the simple version breaks down — when you’re repeating yourself, when you’re writing defensive code against undefined in three places, or when a bug points to a structural issue.
Vaultex
Version 1.0
Theme repository
View the source code, report issues, and contribute to the theme on GitHub.