Promise Anti-Patterns to Avoid in JavaScript
Common promise anti-patterns that cause bugs. Here is each one and the correct approach.
Promise Anti-Patterns to Avoid in JavaScript
Promise anti-patterns are common mistakes that cause bugs or unnecessary complexity. Here is each one and the correct approach.
Anti-Pattern 1: The Explicit Construction Anti-Pattern
// bad: wrapping a promise in new Promise function fetchUser(id) { return new Promise((resolve, reject) => { fetch(`/api/${id}`) .then((res) => resolve(res.json())) .catch((err) => reject(err)); }); } // good: just return the promise function fetchUser(id) { return fetch(`/api/${id}`).then((res) => res.json()); } `` If you already have a promise, do not wrap it in `new Promise`. Just return it or chain `.then`. ### Anti-Pattern 2: The .then Chain That Does Not Return ```js // bad: no return (next .then receives undefined) promise.then((data) => { process(data); }); // good: return promise.then((data) => process(data)); `` ### Anti-Pattern 3: Nested .then (Mini Callback Hell) ```js // bad: nesting promise.then((a) => { otherPromise(a).then((b) => { render(a, b); }); }); // good: chain flatly promise.then((a) => otherPromise(a).then((b) => ({ a, b }))) .then(({ a, b }) => render(a, b)); `` ### Anti-Pattern 4: Using .then's Second Arg Instead of .catch ```js // less good: second arg only catches rejections from the original promise promise.then(onFulfilled, onRejected); // better: .catch catches rejections AND throws from .then promise.then(onFulfilled).catch(onRejected); `` ### Anti-Pattern 5: Sequential await for Independent Operations ```js // slow: sequential const a = await fetchA(); const b = await fetchB(); // fast: parallel const [a, b] = await Promise.all([fetchA(), fetchB()]); `` ### Anti-Pattern 6: Forgetting .catch (Unhandled Rejections) ```js // bad: no .catch fetchP("/api").then((data) => render(data)); // good: .catch fetchP("/api").then((data) => render(data)).catch((err) => handleError(err)); `` ### Anti-Pattern 7: Mixing Callbacks and Promises ```js // bad: mixing fetchP("/api").then((data) => { callbackBasedApi(data, (err, result) => { // now you are back in callback hell }); }); // good: promisify the callback API const callbackApiP = promisify(callbackBasedApi); fetchP("/api").then((data) => callbackApiP(data)).then((result) => render(result)); `` ### Anti-Pattern 8: Using Promise.all for Sequential Operations ```js // bad: Promise.all when you need sequential await Promise.all([fetchA(), fetchBThatDependsOnA()]); // fetchB might run before fetchA completes // good: sequential await const a = await fetchA(); const b = await fetchBThatDependsOnA(a); `` ### The Takeaway Promise anti-patterns: wrapping promises in `new Promise`, not returning from `.then`, nesting `.then`, using `.then`'s second arg instead of `.catch`, sequential `await` for independent operations, forgetting `.catch`, mixing callbacks and promises, and using `Promise.all` for sequential operations. Avoid these for clean, bug-free promise code.
Wrapping a promise in new Promise unnecessarily. If you already have a promise (from fetch, for example), just return it or chain .then. Wrapping it in new Promise and manually calling resolve/reject is redundant and error-prone.
Because it defeats the purpose of promises (creating mini callback hell). Instead of nesting, chain flatly. Or use async/await, which is the cleanest way to sequence async operations.
Because it is slow. If operations are independent, run them in parallel with Promise.all: const [a, b] = await Promise.all([fetchA(), fetchB()]). Sequential await is only correct when operations depend on each other.
Because it creates confusing code and can lead to callback hell inside a promise chain. Promisify the callback API first, then use it in the promise chain. This keeps the code consistent.
It is less robust than .catch. .then(onFulfilled, onRejected) second arg only catches rejections from the original promise. .catch catches rejections AND thrown errors from any .then above it. Prefer .catch.
Ready to master React completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master React
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

