दिन 19: Async JS: Event Loop, Callbacks और Promises
✅ आज आप सीखेंगे
- JavaScript को async code क्यों चाहिए
- Event loop: call stack, task queue, microtasks
- Timers: setTimeout, setInterval, clearTimeout
- Callbacks और callback hell क्यों होता है
- Promises: बनाना, then/catch/finally, Promise.all / allSettled / race / any
🏢 असली दुनिया में
Server से menu load होने में Wi-Fi पर 300 ms और कमज़ोर 4G पर 3 सेकंड लगते हैं। अगर JavaScript इंतज़ार करते हुए कुछ और न करे तो page जम जाएगा – न scroll, न click। Async code browser को network, timer या payment gateway का इंतज़ार करते हुए काम करते रहने देता है। कल का हर API call आज के विचारों पर बनता है।
Synchronous बनाम asynchronous
console.log('1. Take the order');
setTimeout(() => console.log('3. Sweets are ready (after 0 ms!)'), 0);
console.log('2. Take the next customer’s order');JavaScript एक समय में एक काम करता है (single thread)। setTimeout callback को browser/Node को देकर आगे बढ़ जाता है। Callback queue में इंतज़ार करता है जब तक मौजूदा code ख़त्म न हो – तभी event loop उसे चलाता है।
Event loop
console.log('A: script start');
setTimeout(() => console.log('E: setTimeout (task)'), 0);
Promise.resolve().then(() => console.log('C: promise.then (microtask)'));
queueMicrotask(() => console.log('D: queueMicrotask'));
console.log('B: script end');Timers
let seconds = 3;
const id = setInterval(() => {
console.log(`OTP expires in ${seconds}s`);
seconds--;
if (seconds === 0) {
clearInterval(id); // always stop intervals
console.log('OTP expired – request a new one');
}
}, 100); // 100 ms here so the demo is quick
const reminder = setTimeout(() => console.log('This never prints'), 500);
clearTimeout(reminder); // cancelled before it firedCallbacks और callback hell
// Pretend server functions that take time and call us back
function getUser(id, cb) { setTimeout(() => cb(null, { id, name: 'Aarti' }), 50); }
function getOrders(user, cb) { setTimeout(() => cb(null, [{ id: 1042, total: 1800 }]), 50); }
function getInvoice(order, cb) { setTimeout(() => cb(null, `Invoice for #${order.id}: ₹${order.total}`), 50); }
getUser(7, (err, user) => {
if (err) return console.log(err);
getOrders(user, (err, orders) => {
if (err) return console.log(err);
getInvoice(orders[0], (err, invoice) => { // the "pyramid of doom" grows →
if (err) return console.log(err);
console.log(user.name, '→', invoice);
});
});
});हर step और गहरा जाता है, error handling हर स्तर पर दोहरानी पड़ती है और steps साथ-साथ चलाना मुश्किल। Promises (आज) और async/await (कल) ठीक यही हल करते हैं।
Promises
// A promise = an object that will hold a future result: pending → fulfilled OR rejected
function bakeGhewar(kg) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (kg > 20) reject(new Error('We can make at most 20 kg today'));
else resolve(`${kg} kg ghewar ready`);
}, 100);
});
}
bakeGhewar(5)
.then(result => { console.log('✅', result); return bakeGhewar(50); }) // return → chain the next step
.then(result => console.log('never printed', result))
.catch(err => console.log('❌', err.message)) // one catch for the whole chain
.finally(() => console.log('Kitchen closed for today'));| State | मतलब | कौन संभालता है |
|---|---|---|
| pending | अभी चल रहा | — |
| fulfilled | Value के साथ सफलता से पूरा | .then(value => …) |
| rejected | Error के साथ विफल | .catch(err => …) |
| settled (कोई भी) | हो गया, सफल या विफल | .finally(() => …) |
Callback pyramid, promises से दोबारा
const wait = (ms, value) => new Promise(resolve => setTimeout(() => resolve(value), ms));
const getUser = id => wait(50, { id, name: 'Aarti' });
const getOrders = user => wait(50, [{ id: 1042, total: 1800 }]);
const getInvoice = order => wait(50, `Invoice for #${order.id}: ₹${order.total}`);
let currentUser;
getUser(7)
.then(user => { currentUser = user; return getOrders(user); })
.then(orders => getInvoice(orders[0]))
.then(invoice => console.log(currentUser.name, '→', invoice))
.catch(err => console.log('Something failed:', err.message)); // flat, one error handlerPromises एक साथ चलाना
const wait = (ms, v, fail) => new Promise((res, rej) => setTimeout(() => (fail ? rej(new Error(v)) : res(v)), ms));
const menu = wait(120, 'menu');
const offers = wait(80, 'offers');
const reviews = wait(100, 'reviews');
console.time('all');
Promise.all([menu, offers, reviews]).then(r => { console.log('all:', r); console.timeEnd('all'); }); // ~120 ms, not 300
Promise.allSettled([wait(50, 'menu'), wait(60, 'reviews API down', true)])
.then(results => console.log('allSettled:', results.map(r => r.status + ':' + (r.value ?? r.reason.message)).join(', ')));
Promise.race([wait(200, 'slow server'), wait(90, 'timeout – show cached menu')])
.then(winner => console.log('race:', winner));
Promise.any([wait(70, 'mirror 1 down', true), wait(110, 'mirror 2 OK')])
.then(first => console.log('any:', first));| Method | Resolve कब | Reject कब | कब |
|---|---|---|---|
| Promise.all | सब सफल (results का array) | कोई एक fail | Page को menu + offers + cart साथ चाहिए |
| Promise.allSettled | सब पूरे (हर एक की status) | कभी नहीं | Dashboard widgets जो अलग-अलग fail हो सकते हैं |
| Promise.race | पहला settle हो | पहला error से settle हो | Timeouts |
| Promise.any | पहला सफल हो | सब fail | कई mirrors/CDNs में सबसे तेज़ |
असली task: “preparing your order” tracker
<button id="go">Place order</button>
<ol id="steps"></ol>
<script>
const wait = ms => new Promise(r => setTimeout(r, ms));
const steps = document.querySelector('#steps');
function show(text) { const li = document.createElement('li'); li.textContent = text; steps.append(li); }
document.querySelector('#go').addEventListener('click', e => {
e.target.disabled = true;
steps.innerHTML = '';
show('🧾 Order received');
wait(800)
.then(() => { show('👩🍳 Sweets being packed'); return wait(1000); })
.then(() => { show('🛵 Out for delivery'); return wait(1200); })
.then(() => show('✅ Delivered – enjoy!'))
.finally(() => { e.target.disabled = false; });
});
</script>🏅 आज के Job Skills
Practice tasks
🏋️ Practice – ख़ुद करें
Solution देखें
const wait = (ms, v) => new Promise(r => setTimeout(() => r(v), ms));
function timeout(promise, ms) {
const timer = new Promise((_, reject) => setTimeout(() => reject(new Error('Request timed out')), ms));
return Promise.race([promise, timer]);
}
timeout(wait(50, 'menu loaded'), 200).then(console.log).catch(e => console.log(e.message));
timeout(wait(500, 'too slow'), 200).then(console.log).catch(e => console.log(e.message));Solution देखें
console.log(1);
setTimeout(() => console.log(2), 0);
Promise.resolve().then(() => console.log(3));
(async () => { console.log(4); await null; console.log(5); })();
console.log(6);
// expected: 1 4 6 3 5 2Quick quiz
🧠 Quick Quiz – ख़ुद को जाँचें
Interview corner
💼 Interview Corner
Event loop समझाइए।
JavaScript एक call stack पर चलता है। Async operations host (browser/Node) संभालता है; उनके callbacks queues में जाते हैं। Stack ख़ाली होने पर event loop पहले microtask queue ख़ाली करता है (promise reactions, queueMicrotask), फिर अगला task (timers, I/O, events) लेता है, और browsers में tasks के बीच render करता है।
Promise.all बनाम Promise.allSettled?
all सब values के साथ resolve या पहली विफलता पर reject (fail-fast) – जब हर नतीजा ज़रूरी हो। allSettled सबका इंतज़ार करके हर एक की status/value/reason बताता है – जब आंशिक नतीजे उपयोगी हों।
सारांश
- एक thread + event loop; async काम queues में इंतज़ार करता है।
- Microtasks (promises) tasks (timers, events) से पहले चलते हैं।
- Promises: pending → fulfilled/rejected; then/catch/finally; chain के लिए return।
- Parallel काम और timeouts के लिए all / allSettled / race / any।
Day 20: async/await और fetch – loading और error states के साथ API से असली products load करें।
