Async JavaScript & Promises
JavaScript ko network requests, timers aur other delayed work handle karna padta hai bina page ko unnecessarily block kiye. Is chapter me callbacks se Promises aur async/await tak asynchronous flow ko step by step samjhenge.
Synchronous vs asynchronous code
Synchronous statements normally one after another run karte hain. Asynchronous APIs delayed work start kar sakti hain and JavaScript baaki available code continue kar sakta hai.
console.log("Start");
setTimeout(() => {
console.log("Timer finished");
}, 0);
console.log("End");Typical output is Start, End, then Timer finished. A zero-millisecond delay does not mean “run immediately”.
Timer ka callback turant current code ko beech me interrupt nahi karta. Current synchronous work complete hone ke baad hi queued callback run hone ka chance milta hai.
Call stack basics
The call stack tracks currently executing JavaScript functions. A function call stack par add hota hai, aur return hone par remove hota hai.
function second() {
console.log("second");
}
function first() {
second();
}
first();JavaScript execution model ko samajhne ke liye stack important hai because long synchronous work main thread ko busy rakh sakta hai.
Event loop idea
Browser APIs timers, network operations and events ko host environment me handle kar sakti hain. Jab related callback ready hota hai, it is queued. Event loop ready work ko tab execute karne deta hai when the current JavaScript stack is clear.
Tasks and microtasks
Not all queued callbacks same queue use karte hain. Promise handlers are scheduled as microtasks. Timer callbacks are tasks. Current synchronous stack complete hone ke baad pending microtasks are processed before the next task.
console.log("A");
setTimeout(() => console.log("Timer"), 0);
Promise.resolve().then(() => {
console.log("Promise");
});
console.log("B");Typical order: A, B, Promise, Timer.
Callbacks for async work
A callback is a function passed to another function to run later or when some work completes.
function loadLater(callback) {
setTimeout(() => {
callback("Course ready");
}, 500);
}
loadLater(message => {
console.log(message);
});Callbacks are fundamental, but deeply nested dependent callbacks can become harder to read and maintain.
What is a Promise?
A Promise is an object representing the eventual success or failure of an asynchronous operation.
- pending — result not available yet.
- fulfilled — operation completed successfully.
- rejected — operation failed.
Creating a Promise
The Promise constructor receives an executor function with resolve and reject.
function wait(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
wait(500).then(() => {
console.log("500ms completed");
});Most application code consumes Promises returned by APIs or libraries; you do not need to wrap everything in new Promise().
resolve() and reject()
function checkScore(score) {
return new Promise((resolve, reject) => {
if (score >= 0 && score <= 100) {
resolve({ score, valid: true });
} else {
reject(new Error("Score must be between 0 and 100"));
}
});
}Error objects preserve a message and stack information useful for debugging.Consuming with then()
then() handles a fulfilled Promise and returns a new Promise, which makes chaining possible.
checkScore(88)
.then(result => {
console.log(result.score);
return result.score + 5;
})
.then(updatedScore => {
console.log(updatedScore);
});Promise chaining
Return the next value or Promise from each then(). The next handler receives that result.
getStudent()
.then(student => getCourses(student.id))
.then(courses => getProgress(courses[0].id))
.then(progress => console.log(progress));then() but forget to return it, the outer chain may continue before that operation finishes.Handling errors with catch()
catch() handles rejection from earlier Promise steps in the chain.
checkScore(140)
.then(result => console.log(result))
.catch(error => {
console.error(error.message);
});Errors thrown inside a then() handler also reject the Promise returned by that handler.
finally()
finally() runs after settlement whether the Promise fulfilled or rejected. It is useful for cleanup such as hiding a loading indicator.
startOperation()
.then(result => console.log(result))
.catch(error => console.error(error))
.finally(() => {
console.log("Operation finished");
});async functions
An async function always returns a Promise. Returning a normal value automatically fulfills that Promise with the value.
async function getGreeting() {
return "Hello";
}
getGreeting().then(message => {
console.log(message);
});await
await pauses that async function until the awaited Promise settles. It does not freeze the whole browser page while the Promise is pending.
async function showProgress() {
const student = await getStudent();
const courses = await getCourses(student.id);
console.log(courses);
}await Promise-based flow ko synchronous-looking style me likhne deta hai, but function still asynchronous hi rehta hai.
try/catch with async/await
A rejected awaited Promise throws inside the async function, so try/catch can handle it.
async function loadDashboard() {
try {
const student = await getStudent();
const courses = await getCourses(student.id);
console.log(courses);
} catch (error) {
console.error("Could not load dashboard", error);
}
}try/catch/finally
async function saveProgress() {
showLoading();
try {
await sendProgress();
showSuccess();
} catch (error) {
showError(error);
} finally {
hideLoading();
}
}Sequential vs parallel awaits
If operations are independent, starting them one by one may unnecessarily increase total wait time.
const profilePromise = getProfile();
const coursesPromise = getCourses();
const profile = await profilePromise;
const courses = await coursesPromise;Both operations start before the first await. If second operation depends on first result, sequential await is correct.
Promise.all()
Promise.all() waits for all input Promises to fulfill and returns results in input order. If any input rejects, the returned Promise rejects.
const [profile, courses, notifications] = await Promise.all([
getProfile(),
getCourses(),
getNotifications()
]);Promise.allSettled()
Promise.allSettled() waits for every Promise and reports each result as fulfilled or rejected instead of failing fast.
const results = await Promise.allSettled([
loadProfile(),
loadRecommendations(),
loadAnnouncements()
]);
results.forEach(result => {
console.log(result.status);
});Promise.race() and Promise.any()
Promise.race()settles with the first input Promise that settles, whether fulfilled or rejected.Promise.any()fulfills with the first successful input and rejects only when all inputs reject.
These methods solve specific coordination problems; Promise.all() is more common for beginner application flows.
A reusable delay helper
const delay = ms => new Promise(resolve => {
setTimeout(resolve, ms);
});
async function demo() {
console.log("Waiting...");
await delay(1000);
console.log("Done");
}This pattern is useful for demos and controlled timing. Real network calls should not be simulated in production with arbitrary delays.
Unhandled rejections
If a Promise rejects and no code handles the rejection, the environment can report an unhandled rejection. Every meaningful async flow should define where failure is handled or intentionally propagated.
catch blocks make debugging harder and can hide real failures.Async UI states
Real browser interfaces usually need explicit loading, success, empty and error states.
async function loadCourseList() {
setStatus("Loading courses...");
try {
const courses = await getCourses();
renderCourses(courses);
setStatus(courses.length ? "" : "No courses found");
} catch (error) {
setStatus("Could not load courses");
}
}Accessible interfaces should expose meaningful status text and avoid relying only on spinners or color.
Common beginner mistakes
setTimeout(..., 0)ko immediate execution samajhna.- Promise result ko synchronous value ki tarah use karna.
then()chain me next Promise return karna bhoolna.awaitko non-async function ke ordinary code me use karna.- Independent requests ko unnecessarily sequentially await karna.
- Every async function me error ignore karna.
new Promise()se already-Promise-based APIs ko unnecessary wrap karna.- Long synchronous CPU work ko
asynckeyword se automatically non-blocking samajhna. - Loading/error UI states skip karna.
Beginner best practices
- Promise return/await flow ko explicit rakho.
- Dependent work sequentially, independent work parallel run karo.
- Errors ko useful context ke saath handle ya rethrow karo.
- Cleanup ke liye
finallyuse karo when appropriate. - Async functions small and single-purpose rakho.
- UI me loading, empty, success aur failure states plan karo.
- Promise combinators ko intention ke basis par choose karo.
- Network work ko next chapter ke Fetch API ke saath combine karenge.
Chapter checklist
- Synchronous vs asynchronous execution ka basic difference clear hai?
- Call stack aur event loop ka beginner model samajh aaya?
- Promise pending, fulfilled aur rejected states explain kar sakte ho?
then(),catch()aurfinally()use kar sakte ho?asyncfunction aurawaitka behavior clear hai?try/catchse rejected await handle kar sakte ho?- Sequential vs parallel async work ka difference samajh aaya?
Promise.all()aurPromise.allSettled()ka purpose clear hai?
Practice Task — Async Learning Dashboard
Fake async helpers use karke dashboard data flow practice karo.
delay(ms)Promise helper banao.getStudent()async function banao jo delay ke baad student object return kare.getCourses()async function banao jo course array return kare.getNotifications()async function banao.- Promise
then/catchstyle se ek function consume karo. - Same flow ko
async/awaitme rewrite karo. - Ek rejected Promise create karke
try/catchse handle karo. finallyme loading state reset karo.- Independent profile/courses calls ko parallel start karo.
Promise.all()se multiple required results collect karo.Promise.allSettled()se partial failures inspect karo.- Console me sync, Promise microtask aur timer ordering observe karo.
- Loading, empty aur error message states ka DOM plan likho.
- Final code me intentionally forgotten
returnbug add karke chain behavior debug karo.