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().