📘 Callback Function কি?

JavaScript-এ function হলো first-class citizen — অর্থাৎ, তুমি যেভাবে string বা number পাস করো, সেভাবেই function-ও argument হিসেবে পাঠানো যায়
এইরকম function-কে বলা হয় callback — যাকে পরে invoke করা হয় নির্দিষ্ট সময় বা কাজ শেষ হলে।

🎯 সংজ্ঞা:
Callback Function হলো এমন একটি ফাংশন, যেটাকে অন্য একটি ফাংশনের argument হিসেবে পাঠানো হয় এবং সেই parent ফাংশন তাকে “callback” হিসেবে কোনো নির্দিষ্ট সময় বা শর্ত অনুযায়ী execute করে।


📦 Callback কিভাবে কাজ করে?

function doSomethingLater(callback) {
  console.log("Doing something...");
  callback(); // যখন দরকার তখন কল করছি
}

function sayHello() {
  console.log("Hello from callback!");
}

doSomethingLater(sayHello);

👉 এখানে sayHello কে doSomethingLater-এ পাঠানো হয়েছে, এবং শেষে কল করা হয়েছে।
callback() বলার মানে: “আমাকে যেই ফাংশন দিলে, আমি এখন তাকে কল করবো।”


🧪 Callback Function: Real-World Analogy

ধরো তুমি কারো বাসায় যাও, দরজায় বেল বাজাও। কিন্তু দরজা খোলার আগেই তুমি চলে যাও, আর বলে যাও:

“আমি ফিরে আসবো, দরজা খুলে দিলে আমাকে ফোন করে দিও।”

👉 ফোন করা = callback
তুমি কাজ শেষ হওয়ার পরে আবার callback হিসেবে notify হতে চাও।


🔄 Synchronous Callback vs Asynchronous Callback

✅ Synchronous Callback (যখন পরপর execute হয়)

function calculate(num1, num2, operation) {
  return operation(num1, num2); // callback function
}

function add(a, b) {
  return a + b;
}

console.log(calculate(5, 3, add)); // Output: 8

⏳ Asynchronous Callback (যখন কাজ শেষের পরে call হয়)

setTimeout(function () {
  console.log("I am printed after 2 seconds");
}, 2000);

👉 এখানে setTimeout ফাংশন শেষ হওয়ার পরে, নির্দিষ্ট সময় পরে callback চলে।


📁 File/Network Request - Callback Example

function getDataFromServer(callback) {
  setTimeout(() => {
    const data = { id: 1, name: "Yasir" };
    callback(data); // কাজ শেষ হলে data পাঠাচ্ছে
  }, 1000);
}

getDataFromServer(function (result) {
  console.log("Got data:", result);
});

📌 Callback in Array Methods

JavaScript-এ অনেক বিল্ট-ইন মেথড callback নেয়।

.forEach():

[1, 2, 3].forEach(function (item) {
  console.log("Item:", item); // callback
});

.map():

const squared = [1, 2, 3].map((num) => num * num);
console.log(squared); // [1, 4, 9]

⚠️ Callback Hell — Nested Callbacks এর সমস্যা

Callback বারবার nested হলে কোড অস্পষ্ট হয়ে যায়।

loginUser("yasir", () => {
  getProfile(() => {
    getPosts(() => {
      console.log("All done");
    });
  });
});

😱 এটাকে বলে: Callback Hell / Pyramid of Doom Pyramid of Doom

🔧 সমাধান:

  • Promises
  • async/await

✅ Callback এর সুবিধা

সুবিধা ব্যাখ্যা
✨ Flexible Execution Function শেষ হলে কখন কী execute হবে সেটি কন্ট্রোল করা যায়
⏳ Asynchronous Code কাজ শেষ হওয়ার পরেই কোড চালানো যায়
♻️ Reusable Logic একই function-এ বিভিন্ন callback ব্যবহার করে behaviour পরিবর্তন করা যায়

⚠️ Callback এর অসুবিধা

অসুবিধা ব্যাখ্যা
❌ Callback Hell nested callback-এ কোড জটিল হয়ে যায়
🐛 Error Handling জটিল nested হলে try-catch কাজ করে না
🧠 Maintainability কম বড় প্রজেক্টে read করা ও বুঝা কঠিন

✨ Callback → Promise → async/await (Evolution Path)

ফিচার সুবিধা
Callback Control, timing
Promise Clean chaining, error catching
async/await সরলতা ও synchronous feel

📦 Callback Function - Full Practical Use Case:

function loadUser(userId, callback) {
  // simulate API call
  setTimeout(() => {
    const user = { id: userId, name: "Yasir" };
    callback(user); // callback runs here
  }, 1000);
}

function showUser(user) {
  console.log("User Info:", user);
}

loadUser(42, showUser);

🔺 Pyramid of Doom in JavaScript – Callback Hell Explained


Pyramid of Doom কী?

Pyramid of Doom (a.k.a. Callback Hell) হলো এমন এক অবস্থা, যেখানে একাধিক nested callback function ব্যবহারের ফলে কোড দেখতে হয় পিরামিড বা সিঁড়ির মতো।

এই nesting structure:

  • কোডকে জটিল করে তোলে
  • Maintain করা কঠিন হয়
  • Bug ধরাও কঠিন হয়ে পড়ে

🔥 উদাহরণ – Callback Hell (Pyramid of Doom):

loginUser("yasir", function (user) {
  getUserProfile(user.id, function (profile) {
    getUserPosts(profile.id, function (posts) {
      getPostComments(posts[0].id, function (comments) {
        console.log("Done!");
      });
    });
  });
});

⛔ সমস্যা:

  • প্রতি লেভেলে একটি নতুন function ডিফাইন হচ্ছে
  • Code পড়া ও বুঝা কঠিন
  • Error handling একদম জটিল

📐 কেন একে Pyramid বলা হয়?

👀 দেখতে এমন হয়:

function ( ) {
  function ( ) {
    function ( ) {
      function ( ) {
        // Pyramid shaped
      }
    }
  }
}

🧠 Callback Hell কবে হয়?

  • Multiple async task একের পর এক (sequentially) চালাতে হলে
  • প্রতিটি পরবর্তী কাজ আগের কাজের output এর উপর নির্ভর করলে
  • যখন nested callback এর মধ্যে আরেকটি async কাজ করতে হয়

⚠️ Callback Hell এর সমস্যা:

সমস্যা ব্যাখ্যা
😖 কোড জটিল ও unreadable অনেক nesting
🐞 Debug কঠিন কোথায় কী হচ্ছে ধরা যায় না
❌ Error handling কঠিন try-catch কাজ করে না
🔄 Maintainability কম এক লাইনে ভুলে সব ভেঙে যেতে পারে

✅ Callback Hell থেকে মুক্তির উপায়

1️⃣ Named Function দিয়ে Flat Structure:

function onLogin(user) {
  getUserProfile(user.id, onProfile);
}

function onProfile(profile) {
  getUserPosts(profile.id, onPosts);
}

function onPosts(posts) {
  getPostComments(posts[0].id, onComments);
}

function onComments(comments) {
  console.log("Done");
}

loginUser("yasir", onLogin);

🔹 এখানে nested structure এড়ানো হয়েছে।


2️⃣ Use Promises:

loginUser("yasir")
  .then((user) => getUserProfile(user.id))
  .then((profile) => getUserPosts(profile.id))
  .then((posts) => getPostComments(posts[0].id))
  .then((comments) => console.log("Done!"))
  .catch((err) => console.error("Error:", err));

3️⃣ Use async/await:

async function loadUserData() {
  try {
    const user = await loginUser("yasir");
    const profile = await getUserProfile(user.id);
    const posts = await getUserPosts(profile.id);
    const comments = await getPostComments(posts[0].id);
    console.log("Done!");
  } catch (error) {
    console.error("Error:", error);
  }
}
loadUserData();

✅ এইটাই বর্তমানে সবচেয়ে readable, modern ও widely used solution।

🧾 উপসংহার:

দিক Pyramid of Doom সমাধান
কোড গঠন Nested callbacks Named function / Promise
Error Handling দুর্বল .catch() বা try/catch
Readability কম async/await এ বেশি
Maintainability দুর্বল async/await/readable flow