Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      Designing For TV: Principles, Patterns And Practical Guidance (Part 2)

      September 5, 2025

      Neo4j introduces new graph architecture that allows operational and analytics workloads to be run together

      September 5, 2025

      Beyond the benchmarks: Understanding the coding personalities of different LLMs

      September 5, 2025

      Top 10 Use Cases of Vibe Coding in Large-Scale Node.js Applications

      September 3, 2025

      Building smarter interactions with MCP elicitation: From clunky tool calls to seamless user experiences

      September 4, 2025

      From Zero to MCP: Simplifying AI Integrations with xmcp

      September 4, 2025

      Distribution Release: Linux Mint 22.2

      September 4, 2025

      Coded Smorgasbord: Basically, a Smorgasbord

      September 4, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      Drupal 11’s AI Features: What They Actually Mean for Your Team

      September 5, 2025
      Recent

      Drupal 11’s AI Features: What They Actually Mean for Your Team

      September 5, 2025

      Why Data Governance Matters More Than Ever in 2025?

      September 5, 2025

      Perficient Included in the IDC Market Glance for Digital Business Professional Services, 3Q25

      September 5, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      How DevOps Teams Are Redefining Reliability with NixOS and OSTree-Powered Linux

      September 5, 2025
      Recent

      How DevOps Teams Are Redefining Reliability with NixOS and OSTree-Powered Linux

      September 5, 2025

      Distribution Release: Linux Mint 22.2

      September 4, 2025

      ‘Cronos: The New Dawn’ was by far my favorite experience at Gamescom 2025 — Bloober might have cooked an Xbox / PC horror masterpiece

      September 4, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»Development»Promises Made Simple: Understanding Async/Await in JavaScript

    Promises Made Simple: Understanding Async/Await in JavaScript

    April 22, 2025

    JavaScript is single-threaded. That means it runs one task at a time, on one core. But then how does it handle things like API calls, file reads, or user interactions without freezing up?

    That’s where Promises and async/await come into play. They help us handle asynchronous operations without blocking the main thread.

    Let’s break down these concepts in the simplest way possible so whether you’re a beginner or a seasoned dev, it just clicks.

    JavaScript has something called an event loop. It’s always running, checking if there’s work to do—like handling user clicks, network responses, or timers. In the browser, the browser runs it. In Node.js, Node takes care of it.

    When an async function runs and hits an await, it pauses that function. It doesn’t block everything—other code keeps running. When the awaited Promise settles, that async function picks up where it left off.

     

    What is a Promise?

    • ✅ Fulfilled – The operation completed successfully.
    • ❌ Rejected – Something went wrong.
    • ⏳ Pending – Still waiting for the result.

    Instead of using nested callbacks (aka “callback hell”), Promises allow cleaner, more manageable code using chaining.

     Example:

    fetchData()
      .then(data => process(data))
      .then(result => console.log(result))
      .catch(error => console.error(error));
    

     

    Common Promise Methods

    Let’s look at the essential Promise utility methods:

    1. Promise.all()

    Waits for all promises to resolve. If any promise fails, the whole thing fails.

    Promise.all([p1, p2, p3])
      .then(results => console.log(results))
      .catch(error => console.error(error));
    
    • ✅ Resolves when all succeed.
    • ❌ Rejects fast if any fail.
    1. Promise.allSettled()

    Waits for all promises, regardless of success or failure.

    Promise.allSettled([p1, p2, p3])
      .then(results => console.log(results));
    
    • Each result shows { status: “fulfilled”, value } or { status: “rejected”, reason }.
    • Great when you want all results, even the failed ones.
    1. Promise.race()

    Returns as soon as one promise settles (either resolves or rejects).

    Promise.race([p1, p2, p3])
      .then(result => console.log('Fastest:', result))
      .catch(error => console.error('First to fail:', error));
    
    1. Promise.any()

    Returns the first fulfilled promise. Ignores rejections unless all fail.

    Promise.any([p1, p2, p3])
      .then(result => console.log('First success:', result))
      .catch(error => console.error('All failed:', error));
    

    5.Promise.resolve() / Promise.reject

    • resolve(value) creates a resolved promise.
    • reject (value) creates a rejected promise.

    Used for quick returns or mocking async behavior.

     

    Why Not Just Use Callbacks?

    Before Promises, developers relied on callbacks:

    getData(function(response) {
      process(response, function(result) {
        finalize(result);
      });
    });
    

    This worked, but quickly became messy i.e. callback hell.

     

     What is async/await Really Doing?

    Under the hood, async/await is just syntactic sugar over Promises. It makes asynchronous code look synchronous, improving readability and debuggability.

    How it works:

    • When you declare a function with async, it always returns a Promise.
    • When you use await inside an async function, the execution of that function pauses at that point.
    • It waits until the Promise is either resolved or rejected.
    • Once resolved, it returns the value.
    • If rejected, it throws the error, which you can catch using try…catch.
    async function greet() {
      return 'Hello';
    }
    greet().then(msg => console.log(msg)); // Hello
    

    Even though you didn’t explicitly return a Promise, greet() returns one.

     

    Execution Flow: Synchronous vs Async/Await

    Let’s understand how await interacts with the JavaScript event loop.

    console.log("1");
    
    setTimeout(() => console.log("2"), 0);
    
    (async function() {
      console.log("3");
      await Promise.resolve();
      console.log("4");
    })();
    
    console.log("5");
    

    Output:

    Let’s understand how await interacts with the JavaScript event loop.

    1
    3
    5
    4
    2
    

    Explanation:

    • The await doesn’t block the main thread.
    • It puts the rest of the async function in the microtask queue, which runs after the current stack and before setTimeout (macrotask).
    • That’s why “4” comes after “5”.

     

     Best Practices with async/await

    1. Use try/catch for Error Handling

    Avoid unhandled promise rejections by always wrapping await logic inside a try/catch.

    async function getUser() {
      try {
        const res = await fetch('/api/user');
        if (!res.ok) throw new Error('User not found');
        const data = await res.json();
        return data;
      } catch (error) {
        console.error('Error fetching user:', error.message);
        throw error; // rethrow if needed
      }
    }
    
    1. Run Parallel Requests with Promise.all

    Don’t await sequentially unless there’s a dependency between the calls.

    ❌ Bad:

    const user = await getUser();
    const posts = await getPosts(); // waits for user even if not needed
    

    ✅ Better:

    const [user, posts] = await Promise.all([getUser(), getPosts()]);
    1. Avoid await in Loops (when possible)

    ❌ Bad:

    //Each iteration waits for the previous one to complete
    for (let user of users) {
      await sendEmail(user);
    }
    

    ✅ Better:

    //Run in parallel
    await Promise.all(users.map(user => sendEmail(user)));
    

    Common Mistakes

    1. Using await outside async
    const data = await fetch(url); // ❌ SyntaxError
    1. Forgetting to handle rejections
      If your async function throws and you don’t .catch() it (or use try/catch), your app may crash in Node or log warnings in the browser.
    2. Blocking unnecessary operations Don’t await things that don’t need to be awaited. Only await when the next step depends on the result.

     

    Real-World Example: Chained Async Workflow

    Imagine a system where:

    • You authenticate a user,
    • Then fetch their profile,
    • Then load related dashboard data.

    Using async/await:

    async function initDashboard() {
      try {
        const token = await login(username, password);
        const profile = await fetchProfile(token);
        const dashboard = await fetchDashboard(profile.id);
        renderDashboard(dashboard);
      } catch (err) {
        console.error('Error loading dashboard:', err);
        showErrorScreen();
      }
    }
    

    Much easier to follow than chained .then() calls, right?

     

    Converting Promise Chains to Async/Await

    Old way:

    login()
      .then(token => fetchUser(token))
      .then(user => showProfile(user))
      .catch(error => showError(error));
    

    With async/await:

    async function start() {
      try {
        const token = await login();
        const user = await fetchUser(token);
        showProfile(user);
      } catch (error) {
        showError(error);
      }
    }
    

    Cleaner. Clearer. Less nested. Easier to debug.

     

    Bonus utility wrapper for Error Handling

    If you hate repeating try/catch, use a helper:

    const to = promise => promise.then(res => [null, res]).catch(err => [err]);
    
    async function loadData() {
      const [err, data] = await to(fetchData());
      if (err) return console.error(err);
      console.log(data);
    }
    

     

    Final Thoughts

    Both Promises and async/await are powerful tools for handling asynchronous code. Promises came first and are still widely used, especially in libraries. async/awa is now the preferred style in most modern JavaScript apps because it makes the code cleaner and easier to understand.

     

    Tip: You don’t have to choose one forever — they work together! In fact, async/await is built on top of Promises.

     

    Source: Read More 

    Facebook Twitter Reddit Email Copy Link
    Previous ArticleFirebase Cloud Notifications for Laravel
    Next Article when to use map() vs. forEach()

    Related Posts

    Development

    How to Fine-Tune Large Language Models

    September 5, 2025
    Artificial Intelligence

    Scaling Up Reinforcement Learning for Traffic Smoothing: A 100-AV Highway Deployment

    September 5, 2025
    Leave A Reply Cancel Reply

    For security, use of Google's reCAPTCHA service is required which is subject to the Google Privacy Policy and Terms of Use.

    Continue Reading

    CVE-2025-55196 – Kubernetes External Secrets Operator Namespace Bypass Vulnerability

    Common Vulnerabilities and Exposures (CVEs)

    CVE-2023-4533 – Red Hat OpenShift Remote Code Execution

    Common Vulnerabilities and Exposures (CVEs)

    CVE-2010-20007 – Seagull FTP Client Stack-based Buffer Overflow Vulnerability

    Common Vulnerabilities and Exposures (CVEs)

    CVE-2025-4093 – “Firefox ESR and Thunderbird Memory Corruption Vulnerability”

    Common Vulnerabilities and Exposures (CVEs)

    Highlights

    CVE-2025-20666 – “Modem Rogue Base Station Denial of Service Vulnerability”

    May 4, 2025

    CVE ID : CVE-2025-20666

    Published : May 5, 2025, 3:15 a.m. | 17 minutes ago

    Description : In Modem, there is a possible system crash due to an uncaught exception. This could lead to remote denial of service, if a UE has connected to a rogue base station controlled by the attacker, with no additional execution privileges needed. User interaction is not needed for exploitation. Patch ID: MOLY00650610; Issue ID: MSV-2933.

    Severity: 0.0 | NA

    Visit the link for more details, such as CVSS details, affected products, timeline, and more…

    15 Best Free and Open Source Linux Web Servers

    July 27, 2025

    A lifetime’s worth of ChatGPT? OpenAI could launch weekly and lifetime AI subscription plans

    May 10, 2025

    CVE-2025-53537 – LibHTP HTTP Protocol Parsing Memory Leak Vulnerability

    July 23, 2025
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.