Understanding Promises in JavaScript (Made Simple) If you’ve ever struggled with messy callbacks, this is for you - The Problem: Handling asynchronous operations (API calls, timers, etc.) using callbacks often leads to: • Callback hell • Hard-to-read code • Difficult error handling The Solution: Promises A Promise represents the future result of an async operation. It has 3 states: • Pending • Fulfilled • Rejected Basic Example: const fetchData = new Promise((resolve, reject) => { let success = true; if (success) { resolve("Data fetched"); } else { reject("Error fetching data"); } }); fetchData .then(res => console.log(res)) .catch(err => console.log(err)); Why Promises Matter: • Cleaner than callbacks • Better error handling • Easy chaining • Foundation for async/await Pro Tip: If you’re using async/await, you’re already using Promises under the hood! async function getData() { try { const res = await fetchData; console.log(res); } catch (err) { console.log(err); } } Bonus 1: Promise.all() (Must Know) Promise.all([p1, p2, p3]) .then(results => console.log(results)) .catch(err => console.log(err)); Runs all in parallel, fails fast if any fails. Bonus 2: Promise.allSettled() (Underrated) Promise.allSettled([p1, p2, p3]) .then(results => console.log(results)); Returns all results (success + failure) Bonus 3: Promise.race() (Speed Matters) Returns the first settled promise (either success OR failure). const p1 = new Promise(res => setTimeout(() => res("API 1"), 2000)); const p2 = new Promise((_, rej) => setTimeout(() => rej("API 2 failed"), 1000)); Promise.race([p1, p2]) .then(res => console.log(res)) .catch(err => console.log(err)); // "API 2 failed" Key Point: • Fastest result wins • Can return success OR failure • Useful for timeouts Bonus 4: Promise.any() (First Success Wins) Returns the first fulfilled promise and ignores failures. const p1 = Promise.reject("API 1 failed"); const p2 = new Promise(res => setTimeout(() => res("API 2 success"), 1500)); const p3 = new Promise(res => setTimeout(() => res("API 3 success"), 2000)); Promise.any([p1, p2, p3]) .then(res => console.log(res)) // "API 2 success" .catch(err => console.log(err)); Key Point: • Ignores rejected promises • Fails only if ALL promises fail • Best for fallback APIs Real-world usage: • Race → API timeout handling • Any → fallback API strategy • All → parallel API calls • AllSettled → partial results handling Which Promise method do you use the most in real projects? #JavaScript #WebDevelopment #FrontendDeveloper #AsyncProgramming #CodingTips #ReactJS #Angular #SoftwareDevelopment
Mastering JavaScript Promises for Cleaner Async Code
More Relevant Posts
-
🚀 Today we are going to analyse the JavaScript microtask queue, macrotask queue, and event loop. A junior developer once asked me during a code review: "Why does Node.js behave differently even when the code looks simple?" So I gave him a small JavaScript snippet and asked him to predict the output. console.log("Start"); setTimeout(() => { console.log("Timeout"); }, 0); Promise.resolve().then(() => { console.log("Promise"); }); console.log("End"); He answered confidently: Start Timeout Promise End But when we ran the code, the output was: Start End Promise Timeout He looked confused. That’s when we started analysing how JavaScript actually works internally. 🧠 Step 1: JavaScript is Single Threaded JavaScript runs on a single thread. It executes code line by line inside the call stack. So first it runs: console.log("Start") → Start console.log("End") → End Now the stack becomes empty. ⚙️ Step 2: Macrotask Queue setTimeout goes to the macrotask queue. Even though timeout is 0ms, it does not execute immediately. It waits in the macrotask queue. Examples of macrotasks: • setTimeout • setInterval • setImmediate • I/O operations • HTTP requests ⚡ Step 3: Microtask Queue Promise goes to the microtask queue. Examples of microtasks: • Promise.then() • Promise.catch() • Promise.finally() • process.nextTick (Node.js) • queueMicrotask() Microtasks always get higher priority. They execute before macrotasks. 🔁 Step 4: Event Loop Now the event loop starts working. The event loop checks: Is the call stack empty? Yes Check microtask queue Execute all microtasks Then execute macrotasks So execution becomes: Start End Promise Timeout Now everything makes sense. 🏗️ Real Production Example Imagine a Node.js API: app.get("/users", async (req, res) => { console.log("Request received"); setTimeout(() => console.log("Logging"), 0); await Promise.resolve(); console.log("Processing"); res.send("Done"); }); Execution order: Request received Processing Logging Why? Because Promise (microtask) runs before setTimeout (macrotask). This directly affects: • API response time • Logging • Background jobs • Queue processing • Performance optimization 🎯 Why Every Node.js / NestJS / Next.js Developer Should Know This Because internally: • Async/Await uses Promises • API calls use Event Loop • Background jobs use Macrotasks • Middleware uses Microtasks • Performance depends on queue execution Without understanding this, debugging production issues becomes very difficult. 💡 Final Thought JavaScript is not just a language. It is an event-driven execution engine. If you understand microtask queue, macrotask queue, and event loop, you don’t just write code — you understand how the runtime thinks. And once you understand the runtime, you start building faster and more scalable systems. #JavaScript #NodeJS #EventLoop #Microtasks #Macrotasks #NextJS #NestJS #SystemDesign #SoftwareEngineering
To view or add a comment, sign in
-
-
#js #19 **Optional Chaining in Javascript** Optional Chaining (?.) in JavaScript is used to safely access nested properties without causing errors if something is null or undefined. 🔹 Why We Need It Without optional chaining: const user = null; console.log(user.name); // ❌ Error: Cannot read property 'name' 👉 This crashes your code. ✅ With Optional Chaining const user = null; console.log(user?.name); // undefined ✅ (no error) 👉 If user is null or undefined, it stops and returns undefined 🔹 Syntax obj?.propertyobj?.[key]obj?.method() ✅ Examples 📌 1. Nested Objects const user = { profile: { name: "Navnath" }}; console.log(user?.profile?.name); // Navnath console.log(user?.address?.city); // undefined 📌 2. Function Calls const user = { greet() { return "Hello"; }}; console.log(user.greet?.()); // Hello console.log(user.sayHi?.()); // undefined (no error) 📌 3. Arrays const arr = [1, 2, 3]; console.log(arr?.[0]); // 1 console.log(arr?.[5]); // undefined 🔥 Real Use Case (Very Common) const response = { data: { user: { name: "Navnath" } }}; const name = response?.data?.user?.name; 👉 Avoids writing multiple checks like: if (response && response.data && response.data.user) ... ⚠️ Important Points ❌ Doesn’t Work on Undeclared Variables console.log(user?.name); // ❌ if user is not defined at all ⚠️ Stops Only on null / undefined const obj = { value: 0 }; console.log(obj?.value); // 0 ✅ (not skipped) 🔥 Combine with Nullish Coalescing (??) const user = {}; const name = user?.name ?? "Guest"; console.log(name); // Guest 🧠 Easy Memory Trick ?. → "If exists, then access" Otherwise → return undefined, don’t crash #Javascript #ObjectOrientedProgramming #SoftwareDevelopment
To view or add a comment, sign in
-
❓ If JavaScript runs everywhere, but every browser is different… what is actually keeping it consistent ?? And in the era of AI tools like ChatGPT and GitHub Copilot, code generation is no longer the hard part. 👉 So why is this even worth understanding anymore? Most developers casually say: 👉 “The browser runs JavaScript” But that’s not technically accurate. Its partially inaccurate.. And this small misunderstanding leads to an incomplete mental model of how the web actually works. 🧠 The real execution model When browser encounters JavaScript Code : 👉 The JavaScript code is executed by a JavaScript engine. The JS engine is not some physical machine but a piece of code. Every Browser has its own JS Engine. * Chrome → V8 * Firefox → SpiderMonkey * Safari → JavaScriptCore ⚙️ But here’s the important part The JavaScript engine is responsible for: * parsing JavaScript * creating execution context * executing code line by line * converting it into machine understandable code But it is NOT the full system. 🌐 Where the browser comes in The JavaScript engine lives inside the browser. And the browser provides extra capabilities through something called: 👉 Web APIs These are NOT part of JavaScript itself. They are provided by the browser environment. Examples of Web APIs: * setTimeout * fetch (API calls) * DOM events (click, input, scroll) 🧩 So the correct mental model is: 👉 JavaScript Engine → executes code 👉 Browser → provides Web APIs + runtime environment 👉 Event system → handles async behavior and coordination 🚨 Now the real question If every browser has a different JavaScript engine… 👉 How does JavaScript behave the same everywhere? 💡 The answer: ECMAScript standard All JavaScript engines are built to follow a common specification: 👉 ECMAScript (ES specification) This defines: * how JavaScript behaves * how syntax works * how core features execute * how edge cases are handled So even though engines are different internally: 👉 They all follow the same rules That’s what keeps JavaScript consistent across browsers. 💥 So the full picture is: 👉 ECMAScript defines the rules 👉 JavaScript engines implement those rules 👉 Browsers provide Web APIs + runtime environment 👉 Together, they make JavaScript behave consistently everywhere 💡 Why this matters (in today’s world) In the era of AI tools like ChatGPT and GitHub Copilot, code generation is no longer the hard part. 👉 You can generate code in seconds 👉 But when something breaks, AI won’t fix your mental model for you Understanding how the system actually works is what helps you: * debug issues * understand async behavior * make correct architectural decisions And that’s exactly what I’ll try to break down next: 👉 How JavaScript code is actually executed inside the JS engine (step by step) and the interesting fact is JS engine is the piece of code written in C++. #JavaScript #WebDevelopment #AIera
To view or add a comment, sign in
-
I used to manipulate objects directly in JavaScript. Until one day, it didn't work. And the errors were almost impossible to trace. Meanwhile JavaScript has built a clean, deliberate API specifically for the job I had been doing messily for a long time. What is Reflect? Reflect is a built-in JavaScript object that provides a set of methods for performing fundamental operations on objects. The same operations you've always done, but in a more controlled, predictable, and reliable way. Reading properties. Setting values. Checking existence. Deleting keys. Reflect does all of this in a clean way. The most important Reflect methods: -> Reflect.get() - reads a property from an object. const user = { name: "Markus" }; Reflect.get(user, "name"); -> "Markus" Same as user.name - but more explicit and safer in dynamic contexts. -> Reflect.set() - sets a property value and returns true or false. const user = { name: "Markus" }; Reflect.set(user, "name", "John"); -> true console.log(user.name); -> "John" Unlike direct assignment - it tells you whether it succeeded by returning true. -> Reflect.has() - checks if a property exists. Reflect.has(user, "name"); -> true Same as the in operator - but cleaner in functional and dynamic code. -> Reflect.deleteProperty() - deletes a property safely. Reflect.deleteProperty(user, "name"); -> true Same as the delete keyword - but returns a boolean instead of throwing silently. -> Reflect.ownKeys() - returns all keys of an object. const user = { name: "Markus", age: 25}; Reflect.ownKeys(user); -> ["name", "age"] Where Reflect truly shines - with Proxy. Reflect and Proxy are natural partners. Inside a Proxy trap, Reflect lets you perform the default operation in a clean way - without rewriting the behaviour from scratch. Example: const proxy = new Proxy(user, { get(target, key) { console.log(`Reading: ${key}`); return Reflect.get(target, key); -> clean default behaviour } }); Reflect doesn't replace what you already know. It refines it. It makes the operations you perform on objects more intentional, consistent, and significantly easier to debug when something goes wrong.
To view or add a comment, sign in
-
-
Hi everyone, 8 Proven JavaScript Async Patterns Used in Real-World Applications Handling async operations efficiently is critical in modern apps. Here are 8 practical patterns with real usage examples: 1. Async/Await (Clean & Readable) async function getUser() { try { const res = await fetch('/api/user'); const data = await res.json(); console.log(data); } catch (err) { console.error(err); } } 2. Parallel Calls with Promise.all async function loadData() { const [users, posts] = await Promise.all([ fetch('/api/users').then(res => res.json()), fetch('/api/posts').then(res => res.json()) ]); } 3. Handle Partial Failures with Promise.allSettled const results = await Promise.allSettled([ fetch('/api/a'), fetch('/api/b') ]); results.forEach(r => { if (r.status === 'fulfilled') console.log(r.value); }); 4. Sequential Execution (When Order Matters) for (const id of [1, 2, 3]) { const res = await fetch(`/api/user/${id}`); console.log(await res.json()); } 5. Retry Pattern (Basic) async function fetchWithRetry(url, retries = 3) { try { return await fetch(url); } catch (err) { if (retries > 0) return fetchWithRetry(url, retries - 1); throw err; } } 6. Timeout with Promise.race function fetchWithTimeout(url, ms) { return Promise.race([ fetch(url), new Promise((_, reject) => setTimeout(() => reject('Timeout'), ms) ) ]); } 7. Debouncing API Calls (Search Input) function debounce(fn, delay) { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), delay); }; } 8. Queue Processing (Controlled Concurrency) async function processQueue(tasks) { for (const task of tasks) { await task(); } } These patterns help you build: • Faster APIs • Better error handling • Scalable frontend apps #JavaScript #AsyncJS #WebDevelopment #Frontend #NodeJS #CodingTips #SoftwareEngineering
To view or add a comment, sign in
-
𝗥𝗲𝗮𝗰𝘁 𝘃𝘀 𝗝𝗮𝘃𝗮𝗦𝗰𝗿𝗶𝗽𝘁: 𝗪𝗵𝘆 𝗗𝗲𝘃𝗲𝗹𝗼𝗽𝗲𝗿𝘀 𝗣𝗿𝗲𝗳𝗲𝗿 𝗥𝗲𝗮𝗰𝘁 𝗳𝗼𝗿 𝗨𝗜 𝗣𝗿𝗼𝗷𝗲𝗰𝘁𝘀 Have you built a small app? Maybe a calculator or to-do list. You might see it feels harder in plain JavaScript. But in React, it feels easier. Why? React uses JavaScript. So how is it easier? Let me explain simply. In JavaScript, you control everything. In React, you describe what you want. React handles the rest. Think about building a calculator. With JavaScript, you: - Select buttons with getElementById. - Add event listeners to each button. - Store values like current number and operator. - Update the display yourself. - Handle edge cases like clear and delete. You do two jobs. You handle calculations. You update the screen. This is why it feels complex. With React, you: - Create components like Button and Display. - Store values in state. - Update state on click. - React updates the UI automatically. You only focus on your data. React does the rest. Why does React feel easier? Components give clean structure. In React, Display and Buttons are separate parts. In JavaScript, everything mixes together. State makes data management easy. React uses state for changing values. When state changes, the UI updates. In JavaScript, you update variables and the UI separately. No manual DOM work. In JavaScript, you use document.getElementById. In React, you update state. React updates the UI. This saves effort. Reusability is easy. You can use a Button component many times with different values. For bigger projects, React helps. Small apps are fine with JavaScript. But for e-commerce, dashboards, or chat apps, React keeps things organized. So, for UI projects, many developers prefer React. It simplifies the work. Source: https://lnkd.in/gqedqJpf
To view or add a comment, sign in
-
⏱️ 𝗧𝗲𝘀𝘁𝗶𝗻𝗴 𝗔𝘀𝘆𝗻𝗰𝗵𝗿𝗼𝗻𝗼𝘂𝘀 𝗖𝗼𝗱𝗲 𝗶𝗻 𝗝𝗮𝘃𝗮𝗦𝗰𝗿𝗶𝗽𝘁 Async testing in JavaScript is one of those areas where things look correct — but fail silently if done wrong. 📞 🔙 𝗖𝗮𝗹𝗹𝗯𝗮𝗰𝗸-𝗕𝗮𝘀𝗲𝗱 𝗧𝗲𝘀𝘁𝗶𝗻𝗴 When your function depends on callbacks, your test must explicitly tell the test runner when it's done. it("should fetch data (callback)", (done) => { fetchData((err, data) => { if (err) return done(err); expect(data).toBe("hello"); done(); // critical! }); }); ❯❯❯❯ If you see callbacks → use done carefully. ⏳ 𝗣𝗿𝗼𝗺𝗶𝘀𝗲-𝗕𝗮𝘀𝗲𝗱 𝗧𝗲𝘀𝘁𝗶𝗻𝗴 Cleaner than callbacks, but still easy to mess up. You must return the promise from your test. it("should fetch data (promise)", () => { return expect(fetchData()).resolves.toBe("hello"); }); ❯❯❯❯ Always return the promise OR use .resolves/.rejects. 🔄 𝗔𝘀𝘆𝗻𝗰/𝗔𝘄𝗮𝗶𝘁 𝗧𝗲𝘀𝘁𝗶𝗻𝗴 (𝗠𝗼𝗱𝗲𝗿𝗻 𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱) The cleanest and most readable approach. it("should fetch data (async/await)", async () => { const data = await fetchData(); expect(data).toBe("hello"); }); Handling errors - it("should throw error", async () => { await expect(fetchData()).rejects.toThrow("error"); }); ❯❯❯❯ If you use async, always use await where needed. ✍ 𝗞𝗲𝘆 𝗧𝗮𝗸𝗲𝗮𝘄𝗮𝘆𝘀 ♦️ Callbacks → use done() ♦️ Promises → return the promise ♦️ Async/Await → use await properly ♦️ Always test both success AND failure paths. 👉 We’ll dive deeper into 𝗕𝗲𝘀𝘁 𝗣𝗿𝗮𝗰𝘁𝗶𝘀𝗲𝘀 𝗼𝗳 𝗧𝗲𝘀𝘁𝗶𝗻𝗴 in the upcoming posts. Stay tuned!! 🔔 Follow Nitin Kumar for daily valuable insights on LLD, HLD, Distributed Systems and AI. ♻️ Repost to help others in your network. #javascript #nodejs #testing #tdd #mocha #sinon #async
To view or add a comment, sign in
-
-
🚀 JavaScript: The Art of Execution Context & Hoisting (Why it REALLY matters) If you’ve ever wondered why JavaScript behaves the way it does, the answer lies in two core concepts: 👉 Execution Context 👉 Hoisting These aren’t just theory—they define how your code actually runs under the hood. 🧠 1. Execution Context — The Engine Behind Every Line Every time JavaScript runs code, it creates an Execution Context. There are mainly two types: Global Execution Context (GEC) → created when your program starts Function Execution Context (FEC) → created every time a function is invoked 🔄 How it works: Each execution context is created in two phases: 1️⃣ Memory Creation Phase (Hoisting Phase) Variables → stored as undefined Functions → stored with full definition 2️⃣ Code Execution Phase Values are assigned Code runs line by line ⚡ 2. Hoisting — Not Magic, Just Memory Allocation Hoisting is often misunderstood. It doesn’t “move code up”— 👉 it simply means JavaScript allocates memory before execution begins 🔍 Example that explains EVERYTHING console.log(a); // ? console.log(b); // ? console.log(myFunc); // ? var a = 10; let b = 20; function myFunc() { console.log("Hello JS"); } 🧠 Memory Phase: a → undefined b → (in Temporal Dead Zone) myFunc → full function stored 🏃 Execution Phase: console.log(a); // undefined console.log(b); // ❌ ReferenceError console.log(myFunc); // function definition 💣 The TRICKY Part (Arrow Functions vs Normal Functions) console.log(add); const add = () => { return 2 + 3; }; ❓ Output? 👉 ReferenceError: Cannot access 'add' before initialization Why? Because: const variables are hoisted but not initialized They stay in the Temporal Dead Zone (TDZ) So unlike normal functions: console.log(sum); // works function sum() { return 5; } 👉 Function declarations are fully hoisted with definition 👉 But arrow functions behave like variables ❌ 🔥 Key Takeaways ✔ JavaScript creates a new execution context for every function ✔ Memory is allocated before execution starts ✔ var → hoisted as undefined ✔ let / const → hoisted but in TDZ ✔ Function declarations → fully hoisted ✔ Arrow functions → treated like variables 🎯 Why This Matters Understanding this helps you: Debug errors faster ⚡ Write predictable code 🧩 Master interviews 💼 Think like the JavaScript engine 🧠 💡 JavaScript is not weird—you just need to think in terms of execution context. #JavaScript #WebDevelopment #Frontend #Coding #100DaysOfCode #AkshaySaini #Hoisting #ExecutionContext
To view or add a comment, sign in
-
POST 1 — The JavaScript Event Loop Is Not What You Think ⚙️ Every JavaScript developer says they understand the event loop. Most of them don't. And that gap is exactly why async bugs are so hard to find and fix. Here's what's actually happening 👇 ───────────────────────── First — JavaScript is single-threaded. Always. One thread. One call stack. One thing running at a time. So how does it handle timers, fetch calls, and user events without freezing? It doesn't. The BROWSER does. And then it reports back. ───────────────────────── The pieces most developers mix up: The Call Stack → where your code actually runs. Functions get pushed in, executed, and popped out. This is the only place code runs. Web APIs → setTimeout, fetch, DOM events. These live OUTSIDE the JS engine — in the browser or Node runtime. They run in separate threads you never manage. The Task Queue (Macrotask Queue) → where callbacks from Web APIs wait to be picked up. setTimeout callbacks land here. The Microtask Queue → where Promise callbacks and queueMicrotask calls wait. This queue has HIGHER priority than the task queue. ───────────────────────── The loop itself: 1. Run everything currently on the call stack until it's empty 2. Drain the ENTIRE microtask queue — every single item, including new ones added during draining 3. Pick ONE task from the task queue 4. Go back to step 1 ───────────────────────── Why this produces bugs nobody expects: Promise.resolve().then() runs before setTimeout(() => {}, 0) — always. Microtasks can starve the task queue if you keep adding new ones during draining. Long synchronous code blocks EVERYTHING — no timers fire, no events respond, no UI updates. ───────────────────────── The practical rule: Never put heavy computation directly on the call stack. Break it up. Use setTimeout to yield back to the event loop. Keep microtask chains short and predictable. ───────────────────────── Did the microtask vs task queue distinction surprise you? Drop a comment below 👇 #JavaScript #WebDevelopment #FrontendDevelopment #Programming #WebPerformance
To view or add a comment, sign in
-
Day 4: Why doesn't JavaScript get confused? 🧩 Variable Environments & The Call Stack(How Functions works in JS) Today I explored how JavaScript handles multiple variables with the same name across different functions. Using the code below, I took a deep dive into the Variable Environment and the Call Stack. 💻 The Code Challenge: javascript var x = 1; a(); b(); console.log(x); function a() { var x = 10; console.log(x); } function b() { var x = 100; console.log(x); } 🧠 The "Behind the Scenes" Logic: 1️⃣ Global Execution Context (GEC): Memory Phase: x is set to undefined. Functions a and b are stored entirely. Execution Phase: x becomes 1. Then, a() is invoked. 2️⃣ The Function a() Context: A brand new Execution Context is created and pushed onto the Call Stack. This context has its own Variable Environment. The x inside here is local to a(). It logs 10, then the context is popped off the stack and destroyed. 3️⃣ The Function b() Context: Same process! A new context is pushed. Its local x is set to 100. It logs 100, then it's popped off the stack. 4️⃣ Back to Global: Finally, the last console.log(x) runs in the Global context. It looks at the GEC’s Variable Environment where x is still 1. 📚 Key Learnings: Variable Environment: Each execution context has its own "private room" for variables. The x in a() is completely different from the x in the Global scope. Call Stack: It acts as the "Manager," ensuring the browser knows exactly which execution context is currently running. Independence: Functions in JS are like mini-programs with their own memory space. This is the foundation for understanding Lexical Scope and Closures! Watching this happen live in the browser's "Sources" tab makes you realize that JS isn't "magic"—it's just very well-organized! 📂 #JavaScript #WebDevelopment #CallStack #ExecutionContext #ProgrammingTips #FrontendEngineer #CodingLogic
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
Actively looking for Frontend / React Native Developer roles. Open to opportunities in Kolkata or Remote. Happy to connect with recruiters and hiring managers.