Skip to main content

Promises and Async/Await

To resolve "Callback Hell", ES6 introduced the Promise.

A Promise is an object representing the eventual completion (or failure) of an asynchronous operation.

Every Promise resides in one of three states:

  1. Pending: Waiting for the task to finish.
  2. Fulfilled (Resolved): The operation completed successfully.
  3. Rejected: The operation failed.

Consuming a Promise (.then())

const myPromise = new Promise((resolve, reject) => {
let success = true;
if (success) {
resolve("The task finished gracefully!");
} else {
reject("Hardware error occurred!");
}
});

// Consuming the promise cleanly without nested callbacks
myPromise
.then((message) => {
console.log("SUCCESS:", message);
})
.catch((error) => {
console.log("FAILED:", error);
});

Modern Syntax: async / await

In ES8 (2017), JavaScript introduced the async and await keywords, acting as "syntactic sugar" on top of Promises. It allows us to write asynchronous code that visually looks entirely synchronous!

  • async: Placing this keyword in front of a function forces it to automatically return a Promise.
  • await: Can only be used inside an async function. It pauses the local function execution until the Promise resolves, then evaluates securely.
// A fake promise simulating a network delay
const downloadData = () => {
return new Promise(resolve => setTimeout(() => resolve("Data 100%"), 2000));
};

// Modern implementation
async function initTask() {
console.log("Starting download...");

// Execution inside initTask() pauses right here for 2 seconds.
// The rest of the browser remains perfectly unfrozen outside!
const result = await downloadData();

console.log("Finished! Result:", result);
}

initTask();

Error Handling with async/await uses standard try {} catch {} logic blocks instead of relying on .catch().