প্রিন্ট বা পিডিএফ হিসেবে সেভ করুন

ব্রাউজারের প্রিন্ট ডায়ালগে গন্তব্য হিসেবে “Save as PDF” বেছে নিন।

ফিরে যান

UXAtom Learn · JavaScript

ইভেন্ট লুপ

জাভাস্ক্রিপ্ট এক থ্রেডে চলেও কীভাবে একসাথে অনেক কাজ সামলায়।

হালনাগাদ: ৬ আগস্ট ২০২৬ · ২০ মিনিট · ২টি পাঠ

সারাংশ

জাভাস্ক্রিপ্টের একটাই কল স্ট্যাক — মানে এক সময়ে একটার বেশি কাজ চলতে পারে না। তবু নেটওয়ার্ক রিকোয়েস্ট, টাইমার আর ক্লিক একসাথে সামলানো যায়, কারণ ভারী কাজগুলো ভাষাটা নিজে করে না; ব্রাউজার করে। ব্রাউজার কাজ শেষ করে কলব্যাকটা একটা কিউতে রেখে দেয়, আর ইভেন্ট লুপ স্ট্যাক খালি হলে সেটা তুলে নেয়। এই একটা নিয়ম বুঝলে `setTimeout(fn, 0)`-এর দেরি, প্রমিজের আগে চলা, আর "পেজ হ্যাং করে আছে" — তিনটাই একই ব্যাখ্যায় মিলে যায়।

সূচিপত্র

  1. 01কল স্ট্যাক
  2. 02টাস্ক কিউ

কল স্ট্যাক

জাভাস্ক্রিপ্ট যখন একটা ফাংশন ডাকে, সেটা একটা স্ট্যাকের উপরে বসে। ফাংশনটা শেষ হলে স্ট্যাক থেকে নেমে যায়। শেষেরটা আগে নামে — এটাই স্ট্যাক।

JavaScript
function ভেতরে() {
  console.log('ভেতরের কাজ')
}

function বাইরে() {
  ভেতরে()
  console.log('বাইরের কাজ')
}

বাইরে()

বাইরে() ডাকার পর স্ট্যাক দাঁড়ায় [বাইরে], তারপর [বাইরে, ভেতরে]। ভেতরে শেষ হলে নেমে যায়, বাইরে তার পরের লাইনে যায়, তারপর সেও নামে।

স্ট্যাক একটাই

এটাই আসল কথা। ব্রাউজারে জাভাস্ক্রিপ্টের একটাই কল স্ট্যাক, মানে একটাই থ্রেড। এক সময়ে একটাই কাজ চলতে পারে।

তাই যদি একটা ফাংশন অনেকক্ষণ ধরে চলে, আর কিছুই চলতে পারে না — ক্লিক কাজ করে না, অ্যানিমেশন থেমে যায়, স্ক্রল আটকে যায়:

JavaScript
const শুরু = Date.now()
while (Date.now() - শুরু < 5000) {
  // পাঁচ সেকেন্ড ধরে স্ট্যাক দখল করে রাখা
}

এই পাঁচ সেকেন্ড পেজটা পুরোপুরি জমে থাকবে। "পেজ হ্যাং করেছে" বলতে সাধারণত এটাই বোঝায় — কোনো একটা কাজ স্ট্যাক ছাড়ছে না।

তাহলে অ্যাসিঙ্ক কাজ হয় কীভাবে

এখানেই ভুল ধারণাটা তৈরি হয়। fetch() বা setTimeout() জাভাস্ক্রিপ্ট নিজে করে না। এগুলো ব্রাউজারের দেওয়া সুবিধা, আর ব্রাউজারের নিজের আলাদা থ্রেড আছে।

জাভাস্ক্রিপ্ট শুধু বলে দেয় "এই কাজটা করো, শেষ হলে এই ফাংশনটা ডেকো" — তারপর সাথে সাথে পরের লাইনে চলে যায়। স্ট্যাক খালি থাকে।

কাজটা শেষ হলে ব্রাউজার সেই ফাংশনটা কোথায় রাখে, আর কখন সেটা চলার সুযোগ পায় — সেটাই পরের লেখার বিষয়।

টাস্ক কিউ

ব্রাউজার কাজ শেষ করার পর কলব্যাকটা সরাসরি চালায় না। স্ট্যাক তখন ব্যস্ত থাকতে পারে। তাই কলব্যাকটা একটা কিউতে গিয়ে অপেক্ষা করে।

ইভেন্ট লুপের কাজ একটাই, আর সেটা খুব সহজ:

স্ট্যাক খালি? তাহলে কিউ থেকে একটা কাজ তুলে স্ট্যাকে বসাও।

দুটো কিউ, সমান নয়

এখানেই বেশিরভাগ বিভ্রান্তি।

কিউকারা যায়অগ্রাধিকার
মাইক্রোটাস্কপ্রমিজ, queueMicrotask, MutationObserverবেশি
ম্যাক্রোটাস্কsetTimeout, setInterval, ক্লিক, নেটওয়ার্ক ইভেন্টকম

স্ট্যাক খালি হলে ইভেন্ট লুপ পুরো মাইক্রোটাস্ক কিউ খালি করে, তারপর একটা ম্যাক্রোটাস্ক নেয়। একটা নয় — পুরোটা।

JavaScript
console.log('১')

setTimeout(() => console.log('২'), 0)

Promise.resolve().then(() => console.log('৩'))

console.log('৪')

আউটপুট: ১, ৪, ৩, ২।

১ আর ৪ সরাসরি চলে, কারণ ওরা স্ট্যাকেই আছে। তারপর স্ট্যাক খালি হয়। ৩ মাইক্রোটাস্ক, তাই আগে। ২ ম্যাক্রোটাস্ক, তাই শেষে — 0 মিলিসেকেন্ড লেখা থাকা সত্ত্বেও।

মাইক্রোটাস্ক দিয়ে পেজ আটকে দেওয়া

যেহেতু লুপ পুরো মাইক্রোটাস্ক কিউ খালি করে তবেই এগোয়, একটা মাইক্রোটাস্ক যদি নিজেই আরেকটা মাইক্রোটাস্ক যোগ করতে থাকে, কিউ কখনো খালি হয় না:

JavaScript
function চিরকাল() {
  Promise.resolve().then(চিরকাল)
}
চিরকাল()

পেজ জমে যাবে। while (true)-এর মতোই, কিন্তু দেখতে নিরীহ — কারণ কোডে কোনো লুপ নেই।

মনে রাখার মতো

  • স্ট্যাক খালি না হলে কোনো কলব্যাক চলে না।
  • মাইক্রোটাস্ক সবসময় ম্যাক্রোটাস্কের আগে।
  • মাইক্রোটাস্ক কিউ পুরোটা খালি হয়, একটা করে নয়।
  • টাইমারের সময় মানে সর্বনিম্ন দেরি।

ইভেন্ট লুপ — uxatom.com/learn/bn/courses/event-loop