8 JavaScript tricks I use in production code, and the bugs they prevent
These are the modern JavaScript features I reach for most in Node.js APIs, React dashboards and React Native apps. Each one replaces a pattern that quietly causes bugs.
1. ?? instead of || for defaults
const retries = options.retries || 3; // retries: 0 becomes 3
const retries = options.retries ?? 3; // 0 stays 0
|| falls back on anything falsy: 0, '', false. ?? only falls back on null and undefined. Every config value where zero or an empty string is a valid choice needs ??.
2. ??= to cache a promise, not a result
const cache = new Map();
function getUser(id) {
if (!cache.has(id)) cache.set(id, fetchUser(id)); // store the promise
return cache.get(id);
}
// or, with a plain object:
const pending = {};
const getPlan = (id) => (pending[id] ??= fetchPlan(id));
If you cache the awaited result, two calls that arrive at the same time both miss the cache and both hit the database. Cache the promise and the second call waits on the first one. Remember to delete the entry if the promise rejects, or you’ll cache the failure.
3. AbortController for requests that went stale
let controller;
async function search(query) {
controller?.abort(); // cancel the previous request
controller = new AbortController();
const res = await fetch(`/api/search?q=${encodeURIComponent(query)}`, {
signal: controller.signal,
});
return res.json();
}
Without this, a search box shows whichever response arrives last, which isn’t always the latest query. Aborting also frees the connection. For timeouts, AbortSignal.timeout(5000) works in modern browsers and Node.js, and AbortSignal.any([a, b]) combines a timeout with a user cancel.
4. Promise.allSettled when one failure shouldn’t sink the page
const results = await Promise.allSettled([getStats(), getOrders(), getAlerts()]);
const [stats, orders, alerts] = results.map((r) => (r.status === 'fulfilled' ? r.value : null));
Promise.all rejects as soon as one call fails, and a dashboard with three widgets goes blank because one of them timed out. With allSettled each widget handles its own error state.
5. structuredClone for real deep copies
const copy = JSON.parse(JSON.stringify(state)); // Dates become strings, Maps become {}
const copy = structuredClone(state); // Dates, Maps, Sets and cycles survive
The JSON round trip turns Date objects into strings, drops undefined, and throws on circular references. structuredClone handles all of those. It can’t copy functions or class instances’ prototypes, and it isn’t available in every JavaScript runtime, so check your target before relying on it in React Native.
6. toSorted() so React state isn’t mutated
const sorted = items.sort(byPrice); // sorts items in place: state mutated
const sorted = items.toSorted(byPrice); // returns a new array
sort() changes the original array. In React that’s a mutated state object, which leads to renders that don’t happen or happen with the wrong data. toSorted, toReversed and toSpliced (ES2023) return new arrays instead. While you’re there: items.at(-1) reads the last item without items[items.length - 1].
7. Object.groupBy instead of a hand-written reduce
const byStatus = Object.groupBy(orders, (order) => order.status);
// { paid: [...], pending: [...], refunded: [...] }
This replaces the reduce everyone writes slightly differently. It’s ES2024: Node.js 21 and later and current browsers. The result has no prototype, so use Object.hasOwn(byStatus, 'paid') or 'paid' in byStatus rather than calling methods on it.
8. Intl instead of a formatting library
new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(1500);
// "$1,500.00"
new Intl.RelativeTimeFormat('en', { numeric: 'auto' }).format(-1, 'day');
// "yesterday"
Prices, percentages, dates and “3 hours ago” are built in, and they handle locales you’d never think to test. Create the formatter once and reuse it; constructing one inside a render loop is slow.
Where each one works
| Feature | Standard | Node.js |
|---|---|---|
?? | ES2020 | 14+ |
??= | ES2021 | 15+ |
AbortController | Web API | 15+ |
Promise.allSettled | ES2020 | 12.9+ |
structuredClone | Web API | 17+ |
toSorted | ES2023 | 20+ |
Object.groupBy | ES2024 | 21+ |
In the browser, all of these work in current Chrome, Firefox and Safari. In React Native, support depends on your Hermes version, so check before you ship.
If you stream AI responses in a React Native app, the AbortController pattern above is exactly how you stop a model call when the user leaves the screen; I use it in streaming LLM responses to React Native.