Event Loop গভীরভাবে
Call stack, microtask/macrotask, callback queue, rendering — JavaScript কীভাবে async চালায়, গভীর বিশ্লেষণ বাংলায়।
এক thread-এর JavaScript কীভাবে হাজার request-এ বিচলিত হয়? এর উত্তর event loop। stack, queue আর rendering-এর এই গভীর ছবিটুকু বোঝা interview ও দুষ্ট bugs — উভয়ের জন্য জরুরি।
Call stack
function a() {
b();
}
function b() {
c();
}
function c() {
console.log("গভীরতম");
}
a(); // stack: a → b → c — LIFOJavaScript synchronous code call stack-এ একে একে চলে — শেষ-যা-প্রবেশ, প্রথমে-প্রস্থান। infinite recursion-এ stack overflow হয়।
Web APIs (ব্রাউজার/Node)
console.log("১");
setTimeout(() => console.log("২"), 0);
Promise.resolve().then(() => console.log("৩"));
console.log("৪");
// আউটপুট: ১, ৪, ৩, ২setTimeout, fetch, event-এর মতো কাজ browser/Node-এর Web API-তে অফলোড হয়। callback-গুলো পরবর্তী queue-তে বসে। এজন্যই ২-এর আগে ৩ আসে (microtask)।
Microtask বনাম Macrotask
// microtask: Promise.then, queueMicrotask, async/await resumption
// macrotask: setTimeout, setInterval, I/O, event handlers
Promise.resolve().then(() => console.log("micro"));
setTimeout(() => console.log("macro"), 0);
console.log("sync");
// sync → micro → macroযখনই stack খালি, event loop আগে সমস্ত microtask শেষ করে (নতুন-added-ও), তারপর একটি macrotask। তাই ভুল ধারণা: "setTimeout(0) মানে অবিলম্বে" — নয়, microtask-এর পরেও পারে।
Event loop — ধাপে ধাপে
প্রতিটি cycle:
- stack-এ synchronous-কাজ শেষ
- সব microtask queue খালি (প্রতিটি নতুন microtask-সহ)
- একটি macrotask ধরে চালায়
- প্রয়োজনে render (পেইন্ট) — browser-এ
- আবার শুরু
setTimeout(() => console.log("A"), 0);
Promise.resolve()
.then(() => console.log("B"))
.then(() => console.log("C"));
console.log("D");
// D → B → C → ARendering — frame থেকে frame
browser সাধারণত প্রতি frame (প্রায় 16ms/60fps) কিছু কাজ শেষে render করে। দীর্ঘ synchronous block rendering থামিয়ে দেয় — ব্রাউজার "freeze" হয়ে যায়। async-কে ছোট chunk করুন।
function processAll(items) {
let i = 0;
function chunk() {
for (; i < items.length && i < i + 500; i++) {
heavy(items[i]);
}
if (i < items.length) {
setTimeout(chunk, 0); // frame-কে শ্বাস নিতে দিন
}
}
chunk();
}তারপরেও থেমে থাকলে — 5000-item-এর মতো বড় কাজ-এ requestAnimationFrame বা Worker ব্যবহারের কথা ভাবা যায়।
Blocking-কে চেনা
// দীর্ঘ synchronous loop মাউস ও রেন্ডার — দুই-ই থামায়
function heavyLoop() {
for (let i = 0; i < 5_000_000; i++) {
// ভারী হিসাব
}
}
// সমাধান: chunk/async — event loop ও render-কে সুযোগ দিন
সাধারণ guideline: synchronous-এ কী কী block করে সেটা চেনা বেশি দরকারি — ভারী loop/বড় DOM/বড় JSON parse async কৌশলে ভাঙা যায়।
| ভূমিকা | তাই কী |
|---|---|
| Call stack | synchronous কাজ LIFO |
| Microtask queue | Promise.then, async resumption |
| Macrotask queue | setTimeout, I/O, events |
| Event loop | stack-খালি → microtasks → এক macro → render |
setTimeout(0) মানে "অবিলম্বে" নয় — microtask-এর পরেও থাকতে পারে। সন্দেহ হলে কনসোলে চালিয়ে দেখুন।
"Event loop কী?" — সহজ তিন ধাপ: stack, microtask-খালি হওয়া, একটি macrotask; browser-এ frame render। সাথে micro/macro পার্থক্য।
উপরে setTimeout/Promise-এর mix আউটপুট নিজে লিখে কনসোলে run করুন — order-এর prediction অনুশীলন করুন।