Promises and async/await in JavaScript
How Promises work, why async/await is more readable
In JavaScript, some operations don't execute immediately (synchronously), but after some time (asynchronously), for example, getting data from a server or waiting for a response. For such operations, we use Promises and async/await.
In this article, we'll see how Promises work, why async/await is more readable, and how they help you write better, cleaner code.
A Promise is a commitment: "I'll tell you the result when it's ready. Either successfully or with an error."
A Promise has 3 states:
const myPromise = new Promise((resolve, reject) => {
let success = true;
if (success) {
resolve("Everything went well!");
} else {
reject("Something went wrong.");
}
});
myPromise
.then(result => console.log("✅", result))
.catch(error => console.error("❌", error));
This says: when the promise succeeds, then() will execute, and if there's an error, catch() will handle it.
When you get data from an API using fetch, it returns a Promise.
fetch("https://jsonplaceholder.typicode.com/users")
.then(response => response.json())
.then(data => console.log("📦 Data:", data))
.catch(error => console.error("⚠️ Error:", error));
Notice how we can chain multiple then() calls. But this can sometimes become hard to read. This is where async/await comes in.
async/await is a simpler, newer syntax for Promises. It makes code more readable - it looks synchronous but is actually asynchronous.
async function getUsers() {
try {
const response = await fetch("https://jsonplaceholder.typicode.com/users");
const data = await response.json();
console.log("👥 Users:", data);
} catch (error) {
console.error("🚨 Error fetching users:", error);
}
}
getUsers();
await waits until the operation completes, while the try/catch block allows handling errors.
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function demo() {
console.log("⏳ Waiting...");
await wait(2000);
console.log("✅ 2 seconds passed");
}
demo();
This demonstrates how you can implement anything with await - even a simple waiting mechanism.
When you have multiple async operations at once, you can use Promise.all
or Promise.race
.
const promise1 = wait(1000).then(() => "First done");
const promise2 = wait(2000).then(() => "Second done");
Promise.all([promise1, promise2])
.then(results => console.log("✅ All done:", results));
Promise.all()
waits until all completePromise.race()
returns the fastest onePromises are the fundamental way to handle async operations in JavaScript. async/await allows writing Promises in a simpler, more readable way.
Using all these correctly will make your code cleaner, more predictable, and modern.