🚨 "async/await" makes asynchronous code look simple… But it’s also one of the easiest ways to introduce subtle bugs. Over the years, I’ve seen (and made) these mistakes more times than I’d like to admit. Here are some of the most common "async/await" mistakes that can cause real production issues 👇 💡 1. Forgetting to use "await" const data = fetch('/api/users'); // Promise, not actual data console.log(data); ✅ Correct: const data = await fetch('/api/users'); 💡 2. Using "await" inside loops unnecessarily for (const id of ids) { const user = await fetchUser(id); } This runs sequentially and can be painfully slow. ✅ Better: const users = await Promise.all(ids.map(fetchUser)); 💡 3. Missing error handling const data = await fetchData(); If the request fails, your app may crash. ✅ Always wrap critical async calls: try { const data = await fetchData(); } catch (error) { console.error(error); } 💡 4. Mixing ".then()" with "await" const data = await fetch(url).then(res => res.json()); It works, but it’s inconsistent and harder to read. ✅ Prefer one style: const res = await fetch(url); const data = await res.json(); 💡 5. Awaiting independent tasks one by one const user = await fetchUser(); const posts = await fetchPosts(); These can run in parallel. ✅ Better: const [user, posts] = await Promise.all([ fetchUser(), fetchPosts() ]); 💡 6. Not handling rejected promises in "Promise.all()" If one promise fails, the entire batch fails. 👉 Use "Promise.allSettled()" when partial success is acceptable. 🔥 "async/await" improves readability — but understanding how it behaves is what makes your code truly reliable. #JavaScript #JS #es6 #react #reactjs #AsyncAwait #WebDevelopment #Frontend #Programming #SoftwareEngineering
Common async/await mistakes in JavaScript
More Relevant Posts
-
𝐈𝐬 𝐲𝐨𝐮𝐫 𝐮𝐬𝐞𝐄𝐟𝐟𝐞𝐜𝐭 𝐫𝐮𝐧𝐧𝐢𝐧𝐠 𝐭𝐨𝐨 𝐨𝐟𝐭𝐞𝐧, 𝐨𝐫 𝐧𝐨𝐭 𝐚𝐭 𝐚𝐥𝐥 𝐰𝐡𝐞𝐧 𝐲𝐨𝐮 𝐞𝐱𝐩𝐞𝐜𝐭 𝐢𝐭 𝐭𝐨? 𝐘𝐨𝐮'𝐫𝐞 𝐩𝐫𝐨𝐛𝐚𝐛𝐥𝐲 𝐟𝐚𝐥𝐥𝐢𝐧𝐠 𝐟𝐨𝐫 𝐭𝐡𝐢𝐬 𝐜𝐨𝐦𝐦𝐨𝐧 𝐭𝐫𝐚𝐩. One of the sneakiest `useEffect` issues comes from non-primitive values in its dependency array. If you declare a function or object directly inside your component and include it in `useEffect`'s dependencies without memoizing it, React sees a "new" function/object on every render. This means your effect will re-run endlessly, or worse, refer to stale data if you're trying to optimize with an empty array. **Bad Example:** ```jsx function MyComponent() { const fetchData = async () => { /* ... */ }; // New function on every render useEffect(() => { fetchData(); }, [fetchData]); // fetchData changes every render, so effect re-runs } ``` **The Fix:** Memoize your functions with `useCallback` and objects with `useMemo`. This tells React to only create a new instance if its dependencies change. ```jsx import React, { useCallback, useEffect } from 'react'; function MyComponent() { const fetchData = useCallback(async () => { // Your actual data fetching logic console.log("Fetching data..."); }, []); // Depend on nothing if the logic itself doesn't change useEffect(() => { fetchData(); }, [fetchData]); // fetchData only changes if its own dependencies change } ``` This ensures your effect runs only when `fetchData` actually changes (which, in this `useCallback` example, is never after the initial mount, making it efficient). It's a subtle distinction, but mastering `useCallback` and `useMemo` for `useEffect` dependencies is key to stable and performant React apps. Have you ever battled an infinite `useEffect` loop because of this? What was your debugging "aha!" moment? #React #JavaScript #Frontend #WebDevelopment #ReactHooks
To view or add a comment, sign in
-
𝐈𝐬 𝐲𝐨𝐮𝐫 `𝐮𝐬𝐞𝐄𝐟𝐟𝐞𝐜𝐭` 𝐫𝐮𝐧𝐧𝐢𝐧𝐠 𝐰𝐡𝐞𝐧 𝐢𝐭 𝐬𝐡𝐨𝐮𝐥𝐝𝐧'𝐭? 𝐓𝐡𝐞 𝐜𝐮𝐥𝐩𝐫𝐢𝐭 𝐦𝐢𝐠𝐡𝐭 𝐛𝐞 𝐦𝐨𝐫𝐞 𝐬𝐮𝐛𝐭𝐥𝐞 𝐭𝐡𝐚𝐧 𝐲𝐨𝐮 𝐭𝐡𝐢𝐧𝐤. I just spent a frustrating hour debugging a seemingly random data refetch in a React component, only to trace it back to a non-primitive dependency in my `useEffect` array. When you pass an object or a function created inside your component directly into `useEffect`'s dependency array, React performs a reference equality check. Even if the contents of your object or the logic of your function haven't changed, its reference is new on every render. This forces your effect to re-run unnecessarily. Here's the common trap: ```javascript // 🚨 Problematic: 'config' object reference changes on every render const MyComponent = ({ id }) => { const config = { userId: id, status: 'active' }; useEffect(() => { fetchData(config); }, [config]); // 💥 Effect re-runs even if 'id' hasn't changed // ... }; ``` A cleaner, more performant way is to stabilize those references. For configuration objects, `useMemo` is your friend: ```javascript // ✅ Solution: 'memoizedConfig' reference is stable as long as 'id' is const MyComponent = ({ id }) => { const memoizedConfig = useMemo(() => ({ userId: id, status: 'active' }), [id]); useEffect(() => { fetchData(memoizedConfig); }, [memoizedConfig]); // ... }; ``` This prevents wasted renders and unnecessary side effects, keeping your app snappier and less buggy. It's often the small details in `useEffect` that lead to the biggest headaches! Have you ever battled a similar `useEffect` dependency bug? What was your fix? #ReactJS #FrontendDevelopment #JavaScript #WebDev #ReactHooks
To view or add a comment, sign in
-
Most Node.js applications don't crash because of bad architecture. They crash because of basic mistakes. Node.js is robust and scalable, but its asynchronous nature and single-threaded event loop catch many developers off guard. Simple oversights can slowly degrade performance or take down your entire server silently. Here are the most common Node.js mistakes and how to avoid them: 1. Blocking the Event Loop Since Node is single-threaded, running heavy synchronous operations (like complex calculations or giant JSON parsing) blocks all other requests from processing. Always offload heavy tasks. 2. The "Headers Already Sent" Error This happens when you try to send a response to the client more than once. Developers often forget to explicitly use "return" after an early response. 3. Unhandled Promise Rejections If you don't wrap your async operations in try/catch or use .catch(), an unhandled rejected promise can crash your Node process altogether. 4. Mixing Callbacks and Promises This leads to chaotic, unreadable code. Stick to modern async/await to keep your control flow linear and clean. 5. Running Development Mode in Production Failing to set NODE_ENV=production means Express and other libraries will skip crucial caching and performance optimizations. Here is a classic example of the early return mistake: ```javascript app.get('/user', (req, res) => { if (!req.query.id) { res.status(400).json({ error: 'ID is required' }); // MISTAKE: Execution continues because of missing 'return' } // This will still execute, causing a "headers already sent" crash. res.status(200).json({ success: true, user: "John Doe" }); }); ``` Key takeaways: - Never block the event loop with heavy sync tasks. - Always return early when sending error responses. - Handle all async errors diligently. - Use the correct environment variables for production. What was the most frustrating Node.js mistake you made when starting out? Let me know below. #nodejs #javascript #webdevelopment #backend #softwareengineering #coding #programming #tech #webdev #expressjs
To view or add a comment, sign in
-
-
Most React devs think they understand useEffect. They don't. And it's costing them subtle bugs in prod. Here's the one thing nobody explains clearly: The cleanup function doesn't run when you think it does. Say you're fetching user data based on a userId prop: > the buggy version useEffect(() => { fetch(`/api/user/${userId}`) .then(res => res.json()) .then(data => setUser(data)); }, [userId]); Looks fine, right? It's not. If userId changes from 1 → 2 quickly, maybe the user is clicking through a list, both requests are in flight. Whichever resolves last wins. You could end up showing user 1's data on user 2's profile. That's a race condition, and it's completely silent. Here's how you fix it with an AbortController: > the correct version useEffect(() => { const controller = new AbortController(); fetch(`/api/user/${userId}`, { signal: controller.signal }) .then(res => res.json()) .then(data => setUser(data)) .catch(err => { if (err.name !== 'AbortError') throw err; }); return () => controller.abort(); }, [userId]); Now when userId changes, React runs the cleanup - which aborts the in-flight request, before firing the new effect. No stale data. No race. No mystery bug at 2am. The cleanup function is not just for "removing event listeners." It's your undo button for whatever the effect started. Timers? Clear them. Subscriptions? Unsubscribe. Requests? Abort them. I've seen this bite senior devs on dashboards, search inputs, and paginated lists more times than I can count. If your useEffect fetches data and has no cleanup, there's a bug waiting to happen. #React #MERN #WebDevelopment #JavaScript #FrontendDevelopment #ReactNative
To view or add a comment, sign in
-
I promised — and I delivered. Here's usePromise: a custom React hook I built that I genuinely believe should be in every developer's project from day one. Let me explain why. The problem nobody talks about openly: Every React developer has written this exact block of code hundreds of times mentioned in the image 👇 It works. It's familiar. And it's been silently violating the DRY principle across every codebase you've ever touched. usePromise replaces all of that with a single hook that handles: ✅ Loading, data, and error state — managed via useReducer to prevent async race conditions ✅ Real request cancellation via AbortController (not just ignoring the response — actually aborting the request) ✅ Data transformation at the configuration level with dataMapper ✅ Lifecycle callbacks — onSuccess, onError, onComplete, and isRequestAbortionComplete ✅ executeOnMount support — fire on render without a single useEffect in your component ✅ Full reset capability — return to initial state cleanly Why not just React Query? React Query is excellent for caching, deduplication, and large-scale data orchestration. But sometimes you want something you fully own — no black boxes, no magic, no dependency debates in code review. usePromise gives you that. It's a foundation you understand end-to-end and can extend however you need. Why should this be standard? SOLID principles tell us: don't repeat yourself. Async data fetching is the most repeated pattern in every React application in existence. The framework gives us the primitives — useReducer, useCallback, useEffect — but leaves the wiring entirely to us. Every team solves this problem. Most teams solve it inconsistently. This hook is the consistent answer. Three years in, and the thing I keep coming back to is this: the first few years of your career build the developer you'll be. The habits, the patterns, the defaults you reach for. Reach for clean ones. Full deep-dive article on Medium including the complete implementation, the Promise lifecycle explained from first principles, and an honest breakdown of trade-offs. This is the medium article for more clarity down below 👇 https://lnkd.in/gJWZhQXk #React #JavaScript #WebDevelopment #Frontend #OpenSource #ReactHooks #CleanCode
To view or add a comment, sign in
-
-
I used to wonder why my Node.js server slowed to a crawl under load. Then I truly understood the event loop. 💡 Here's what changed — with real examples. 🔷 THE CORE IDEA Node.js runs on a single thread. But it handles thousands of concurrent operations without breaking a sweat. The secret? It never waits. When Node.js hits an async operation — a DB call, an API request, a file read — it hands it off to the system and keeps moving. The event loop picks up the result when it's ready and executes the callback. This is why Node.js excels at I/O-heavy workloads. 🔷 WHERE IT WINS IN THE REAL WORLD ✅ High-concurrency APIs Handling 10,000 simultaneous requests? Node.js doesn't spin up 10,000 threads. It processes each callback as responses arrive — lean and efficient. ✅ Real-time applications Chat apps, live notifications, collaborative tools — all powered by the event loop's ability to handle thousands of WebSocket connections without dedicated threads per user. ✅ Streaming data Video streaming, large file transfers — Node.js streams chunks of data through the event loop continuously, keeping memory usage low. 🔷 WHERE IT BREAKS — AND HOW TO FIX IT ❌ CPU-intensive tasks on the main thread Running image compression, PDF generation, or complex calculations synchronously blocks the event loop. Every other request waits. → Fix: Use worker_threads or offload to a background job queue. ❌ Deeply nested synchronous loops A for loop processing 1 million records on the main thread starves the event loop. → Fix: Break work into async chunks or use streams. ❌ Misunderstanding setTimeout() setTimeout(fn, 0) doesn't mean immediate. It means "after the current stack clears and when the event loop gets to it." → Fix: Use setImmediate() or process.nextTick() when execution order matters. 🔷 THE GOLDEN RULE The event loop is the heartbeat of your Node.js server. Every millisecond you block it, every user feels it. Write async code. Offload heavy work. Understand your phases. That's how you build Node.js apps that scale. 🚀 What's the most unexpected event loop issue you've debugged? I'd love to hear it 👇 #NodeJS #JavaScript #BackendDevelopment #EventLoop #WebPerformance #SoftwareEngineering #FullStackDevelopment #TechTips #AsyncProgramming #NodeJSDeveloper
To view or add a comment, sign in
-
🚀 Why You Should Use React Query (TanStack Query) in Your Next Project If you're still managing server state manually with useEffect + useState… you're making life harder than it needs to be. Here’s why React Query is a game-changer 👇 🔹 1. Smart Data Fetching React Query handles caching, background updates, and synchronization automatically — no need to write repetitive API logic. 🔹 2. Built-in Caching Data is cached by default, which means faster UI and fewer unnecessary API calls. 🔹 3. Automatic Refetching It can refetch data in the background when the window refocuses or network reconnects. 🔹 4. Easy Loading & Error States No more manual flags — React Query gives you clean states like isLoading, isError, isSuccess out of the box. 🔹 5. Pagination & Infinite Scroll Handling pagination becomes super simple with built-in support. 🔹 6. Better Developer Experience Cleaner code, less boilerplate, and improved maintainability. 💡 In short: React Query lets you focus on building features instead of managing server state. Have you tried React Query yet? Share your experience 👇 #ReactJS #WebDevelopment #Frontend #JavaScript #Programming #Developers #Tech
To view or add a comment, sign in
-
-
Node.js is single-threaded. So why doesn’t your server freeze with 10,000 requests? This confused me for months — until I understood the event loop. Here’s the mental model that made it click The 4 pieces you need to understand 1. JS Engine (e.g. V8) Executes your JavaScript by parsing → compiling → running it, while managing memory (heap) and execution flow (call stack) 2. Call Stack A single-threaded execution stack where synchronous code runs one function at a time — if it’s occupied by heavy work, nothing else (including callbacks) can run 3. Web APIs / Node APIs (libuv) Background system that takes over async operations (timers, file system, network, DB), so the JS engine doesn’t block while waiting 4. Queues Hold ready callbacks — microtasks (Promises) are processed immediately after current execution, while task queue (timers/I/O) runs only when the stack is free 🔁 The rule everything follows 1. Run all synchronous code (call stack) 2. Execute ALL microtasks (Promises) 3. Execute ONE task (timers, I/O) 4. Repeat 🍽️ Mental model Node is a single chef Takes orders (requests) Hands off long work (async APIs) Keeps working instead of waiting Comes back when tasks are ready ⚠️ If the chef is stuck → everything stops #nodejs #javascript #nestjs #backend #softwareengineering
To view or add a comment, sign in
-
-
Do you actually know how React + Next.js talk to the server? Most devs think it’s just “API calls”… but that’s not what’s really happening. With modern React + Next.js, the communication is built on top of the React Server Components (RSC) protocol a streaming model where the server sends serialized component trees (not just JSON). That means: → The server is literally sending UI instructions → The client reconstructs the tree → Everything depends on strict runtime contracts And here’s where things get interesting… Why pre-compilers break this? - Pre-compilers assume code is static. But RSC is not static it’s a live protocol. When you introduce a pre-compiler, you risk: - Breaking the serialization format - Changing module boundaries - Losing execution context between server ↔ client This isn’t theoretical. There are real cases where: → server actions crash builds → turbopack behaves differently from webpack → rendering fails during compilation All because the system expects a very specific execution model Even security issues have emerged from this layer, where malformed requests could affect server execution in the RSC pipeline That’s exactly why I built a fix for pre-compilers. Instead of treating prompts/code as strings, we: → respect the execution graph → preserve boundaries → align with how RSC actually works If you're building tooling around Next.js, this layer is where everything either works… or completely breaks. https://lnkd.in/dwTutPkr #nextjs #reactjs #webdev #softwareengineering #frontend #ai #programming #buildinpublic
To view or add a comment, sign in
-
🚨 Most developers use Fetch… but still get it wrong Not because it’s hard— but because of ONE hidden detail 👇 👉 Fetch does NOT fail on HTTP errors So even if your API returns: ❌ 404 ❌ 500 Your code still runs like everything is fine 😬 💡 The fix? Always check res.ok before using the data 🔥 Key takeaway: Fetch = Promise-based NOT = automatic error handling This tiny mistake can break real apps Save this before your next interview 🚀 Have you run into this before? 👇 #JavaScript #Frontend #WebDevelopment #CodingTips #Developers
To view or add a comment, sign in
-
Explore content categories
- Career
- Productivity
- Finance
- Soft Skills & Emotional Intelligence
- Project Management
- Education
- Technology
- Leadership
- Ecommerce
- User Experience
- Recruitment & HR
- Customer Experience
- Real Estate
- Marketing
- Sales
- Retail & Merchandising
- Science
- Supply Chain Management
- Future Of Work
- Consulting
- Writing
- Economics
- Artificial Intelligence
- Employee Experience
- Workplace Trends
- Fundraising
- Networking
- Corporate Social Responsibility
- Negotiation
- Communication
- Engineering
- Hospitality & Tourism
- Business Strategy
- Change Management
- Organizational Culture
- Design
- Innovation
- Event Planning
- Training & Development
Really well put. Async/await makes things look synchronous, which is exactly why these bugs slip through. The Promise.all vs sequential await point is something I've seen impact performance massively in production.