Free tutorials & notes in Hindi & English · Clean code examples 🧰 Free PDF & Image Tools →
⚡ Days 15–22 – Advanced & Async JavaScript  ·  Day 19

Day 19: Async JS: Event Loop, Callbacks & Promises

⏱ 100 min📶 Intermediate → Pro🎯 100% self-study
Day 19 / 30

✅ Today you will learn

  • Why JavaScript needs async code
  • The event loop: call stack, task queue, microtasks
  • Timers: setTimeout, setInterval, clearTimeout
  • Callbacks and why callback hell happens
  • Promises: create, then/catch/finally, Promise.all / allSettled / race / any

🏢 In the real world

Loading the menu from a server takes 300 ms on Wi-Fi and 3 seconds on a weak 4G signal. If JavaScript waited and did nothing else, the page would freeze – no scrolling, no clicking. Async code lets the browser keep working while it waits for the network, a timer or a payment gateway. Every API call you make tomorrow builds on today’s ideas.

Synchronous vs asynchronous

JavaScript
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');
1. Take the order 2. Take the next customer’s order 3. Sweets are ready (after 0 ms!)
🧠 Why does 3 print last even with 0 ms?

JavaScript runs one thing at a time (single thread). setTimeout hands the callback to the browser/Node and moves on. The callback waits in a queue until the current code finishes – only then does the event loop run it.

The event loop

Call stack runs your code line by lineAsync work (timers, fetch, clicks) is handed to the browserWhen ready, callbacks wait in queuesMicrotasks first (promise .then), then tasks (setTimeout, events)Event loop moves the next callback to the empty stack
How one thread handles many things
JavaScript
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');
A: script start B: script end C: promise.then (microtask) D: queueMicrotask E: setTimeout (task)

Timers

JavaScript
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 fired
OTP expires in 3s OTP expires in 2s OTP expires in 1s OTP expired – request a new one

Callbacks and callback hell

JavaScript
// 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);
    });
  });
});
Aarti → Invoice for #1042: ₹1800
⚠️ The problem with nested callbacks

Each step nests deeper, error handling is repeated at every level and running steps in parallel is hard. Promises (today) and async/await (tomorrow) solve exactly this.

Promises

JavaScript
// 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'));
✅ 5 kg ghewar ready ❌ We can make at most 20 kg today Kitchen closed for today
StateMeaningHandled by
pendingStill working—
fulfilledFinished successfully with a value.then(value => …)
rejectedFailed with an error.catch(err => …)
settled (either)Done, success or failure.finally(() => …)

The callback pyramid, rewritten with promises

JavaScript
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 handler
Aarti → Invoice for #1042: ₹1800

Running promises together

JavaScript
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));
allSettled: fulfilled:menu, rejected:reviews API down race: timeout – show cached menu any: mirror 2 OK all: [ 'menu', 'offers', 'reviews' ] all: 120.393ms
MethodResolves whenRejects whenUse for
Promise.allAll succeed (array of results)Any one failsPage needs menu + offers + cart together
Promise.allSettledAll finish (status of each)NeverDashboard widgets that may fail independently
Promise.raceThe first settlesThe first settles with an errorTimeouts
Promise.anyThe first succeedsAll failFastest of several mirrors/CDNs

Real task: a “preparing your order” tracker

HTML + JavaScript
<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>
▶  A promise chain driving the UI step by step

🏅 Job skills unlocked today

✔ Explain the event loop and microtask order✔ Use setTimeout, setInterval and clear them✔ Create, chain and handle promises✔ Run work in parallel with Promise.all/allSettled/race/any

Practice tasks

🏋️ Practice – do it yourself

Task 1: Write timeout(promise, ms) that rejects with “Request timed out” if the promise takes longer than ms (use Promise.race).
Show solution
JavaScript
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));
menu loaded Request timed out
Task 2: Predict the order of the logs, then run.
Show solution
JavaScript
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 2
1 4 6 3 5 2
Task 3: Make a “Resend OTP in 30s” button that is disabled and counts down with setInterval, then becomes active again.

Quick quiz

🧠 Quick Quiz – test yourself

1. JavaScript in the browser is…
One call stack.
2. Which runs first?
Microtasks before tasks.
3. Stop a repeating timer:
Keep the id.
4. Promise.all rejects when…
Use allSettled to see each result.
5. Inside .then, returning a promise…
That is chaining.

Interview corner

💼 Interview Corner

Explain the event loop.

JavaScript executes on a single call stack. Async operations are handled by the host (browser/Node); their callbacks go to queues. When the stack is empty the event loop first drains the microtask queue (promise reactions, queueMicrotask), then takes the next task (timers, I/O, events), and renders between tasks in browsers.

Promise.all vs Promise.allSettled?

all resolves with all values or rejects on the first failure (fail-fast) – use when every result is required. allSettled waits for all and reports each status/value/reason – use when partial results are useful.

Summary

  • One thread + event loop; async work waits in queues.
  • Microtasks (promises) run before tasks (timers, events).
  • Promises: pending → fulfilled/rejected; then/catch/finally; return to chain.
  • all / allSettled / race / any for parallel work and timeouts.
➡️ Next

Day 20: async/await and fetch – load real products from an API with loading and error states.

Frequently Asked Questions

Is setTimeout exact?
No – it is a minimum delay. If the page is busy or the tab is in the background, it can run later.
Do I still need to learn .then if async/await exists?
Yes – async/await is built on promises, many libraries return promises, and Promise.all/race are used with both styles.
← JavaScript (30 Days)
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

Next topicDay 20: async/await & fetch: Working with APIs Your progress: 19 / 30 (63%) · Lesson 20 / 30 Continue →

How was this lesson?

Your feedback helps us make the content better.

Write a review or suggestion (optional)

After approval, your name and city may appear publicly with your review. Please do not write your email or phone number.

▶ CodingEasily on YouTube

Learn with video lessons in easy Hindi

Featured video: RDBMS Part 3 – Class XI Commerce IT

▶ Subscribe – it’s free