Advance JavaScript শিখুন বাংলায় (পর্ব ১০) — Error Handling বিস্তারিত শিখুন

Error Handling বিস্তারিত

আগের পর্বে আমরা localStorage-এ Class instance সংরক্ষণ শিখেছিলাম। এই পর্বে আমরা দেখব Error Handling বিস্তারিতভাবে — try/catch/finally-এর সঠিক ব্যবহার, আর কাস্টম এরর ক্লাস বানানো — যা পর্ব ৮-এর Inheritance-এর একটা বাস্তব প্রয়োগ।

try/catch/finally রিক্যাপ

বেসিক স্ট্রাকচার মনে করিয়ে দেওয়া যাক — try-তে যে কোড এরর দিতে পারে সেটা রাখা হয়, catch-এ এরর হ্যান্ডেল করা হয়, আর finally-তে যা লেখা থাকে সেটা এরর হোক বা না হোক, সবসময় রান হয়।

function divide(a, b) {
  try {
    if (b === 0) {
      throw new Error("শূন্য দিয়ে ভাগ করা যায় না");
    }
    return a / b;
  } catch (error) {
    console.log("এরর ধরা পড়েছে:", error.message);
    return null;
  } finally {
    console.log("এই লাইনটা সবসময় রান হবে, এরর হোক বা না হোক");
  }
}

divide(10, 2); // ৫ রিটার্ন করবে, finally-ও রান হবে
divide(10, 0); // null রিটার্ন করবে, catch আর finally দুটোই রান হবে

finally-এর সবচেয়ে সাধারণ ব্যবহার: ক্লিনআপ কাজ — যেমন লোডিং স্পিনার বন্ধ করা, ফাইল হ্যান্ডেল বন্ধ করা, বা কানেকশন ছেড়ে দেওয়া — এসব এরর হোক বা না হোক করতেই হবে।

async function loadData() {
  showLoadingSpinner();
  try {
    const data = await fetch("/api/data");
    return data.json();
  } catch (error) {
    showErrorMessage(error.message);
  } finally {
    hideLoadingSpinner(); // সফল হোক বা ব্যর্থ, স্পিনার বন্ধ করতেই হবে
  }
}

কাস্টম Error ক্লাস — Inheritance-এর বাস্তব প্রয়োগ

শুধু new Error("বার্তা") ব্যবহার করলে সব এরর একই রকম দেখায়। JavaScript-এর বিল্ট-ইন Error ক্লাসকে extend করে নিজের মতো বিশেষায়িত এরর টাইপ বানানো যায় — যা আগের পর্বের extends/super-এরই বাস্তব প্রয়োগ।

class ValidationError extends Error {
  constructor(message, field) {
    super(message); // Error ক্লাসের constructor কল করা
    this.name = "ValidationError"; // এরর টাইপ চেনার জন্য নাম দেওয়া
    this.field = field; // অতিরিক্ত কাস্টম তথ্য
  }
}

class NetworkError extends Error {
  constructor(message, statusCode) {
    super(message);
    this.name = "NetworkError";
    this.statusCode = statusCode;
  }
}

function validateEmail(email) {
  if (!email.includes("@")) {
    throw new ValidationError("ইমেইল সঠিক না", "email");
  }
}

try {
  validateEmail("wrong-email");
} catch (error) {
  console.log(error.name); // "ValidationError"
  console.log(error.message); // "ইমেইল সঠিক না"
  console.log(error.field); // "email" — কাস্টম প্রপার্টি
}

একাধিক এরর টাইপ আলাদাভাবে হ্যান্ডেল করা

কাস্টম এরর ক্লাসের সবচেয়ে বড় সুবিধা — instanceof দিয়ে চেক করে ভিন্ন ভিন্ন এরর টাইপের জন্য ভিন্ন ভিন্ন প্রতিক্রিয়া দেওয়া যায়।

async function submitForm(data) {
  try {
    validateEmail(data.email);
    const response = await fetch("/api/submit", { method: "POST", body: JSON.stringify(data) });
    if (!response.ok) {
      throw new NetworkError("সার্ভার এরর", response.status);
    }
  } catch (error) {
    if (error instanceof ValidationError) {
      showFieldError(error.field, error.message); // ফর্ম ফিল্ডে হাইলাইট করা
    } else if (error instanceof NetworkError) {
      showToast(`সার্ভার এরর (${error.statusCode})`); // টোস্ট নোটিফিকেশন
    } else {
      console.error("অজানা এরর:", error); // যা প্রত্যাশিত ছিল না
    }
  }
}

এভাবে প্রতিটা এরর টাইপের জন্য আলাদা, উপযুক্ত UI প্রতিক্রিয়া দেখানো যায় — ভ্যালিডেশন এরর হলে ফর্ম ফিল্ডে লাল বর্ডার, নেটওয়ার্ক এরর হলে টোস্ট মেসেজ।

লাইভ ডেমো — বিভিন্ন এরর টাইপ আলাদাভাবে দেখানো

নিচের বাটনগুলো ইচ্ছাকৃতভাবে ভিন্ন ভিন্ন কাস্টম এরর থ্রো করে — লক্ষ্য করো প্রতিটার জন্য ভিন্ন মেসেজ দেখানো হচ্ছে।

async/await-এ এরর হ্যান্ডলিং

async ফাংশনে throw করা যেকোনো এরর স্বয়ংক্রিয়ভাবে একটা reject হওয়া Promise-এ পরিণত হয় — তাই try/catch দিয়েই সেটা ধরা যায়, আলাদা করে .catch() লাগে না।

async function fetchBook(id) {
  const response = await fetch(`/api/books/${id}`);

  if (!response.ok) {
    throw new NetworkError("বই খুঁজে পাওয়া যায়নি", response.status);
  }

  return response.json();
}

async function displayBook(id) {
  try {
    const book = await fetchBook(id);
    console.log(book);
  } catch (error) {
    // fetchBook-এর ভেতরের throw এখানে ধরা পড়ছে
    console.log("বই লোড করা যায়নি:", error.message);
  }
}

error.cause — এরর চেইনিং

আধুনিক JavaScript-এ একটা এরর অন্য একটা এররের কারণে হয়েছে সেটা cause দিয়ে ট্র্যাক করা যায় — এতে ডিবাগ করার সময় মূল কারণ খুঁজে পাওয়া সহজ হয়।

async function saveBookToLibrary(book) {
  try {
    await saveToDatabase(book);
  } catch (originalError) {
    throw new Error("বই সেভ করা যায়নি", { cause: originalError });
  }
}

try {
  await saveBookToLibrary(myBook);
} catch (error) {
  console.log(error.message); // "বই সেভ করা যায়নি"
  console.log(error.cause); // মূল database এরর, ডিবাগের জন্য দরকারি
}

একটা সম্পূর্ণ উদাহরণ — ফর্ম ভ্যালিডেশন সিস্টেম

চলো একাধিক কাস্টম এরর ক্লাস মিলিয়ে একটা বাস্তব ফর্ম ভ্যালিডেশন সিস্টেম বানাই।

class ValidationError extends Error {
  constructor(message, field) {
    super(message);
    this.name = "ValidationError";
    this.field = field;
  }
}

function validateBookForm(data) {
  if (!data.title || data.title.trim() === "") {
    throw new ValidationError("শিরোনাম আবশ্যক", "title");
  }
  if (!data.author || data.author.trim() === "") {
    throw new ValidationError("লেখকের নাম আবশ্যক", "author");
  }
  if (data.pageCount && data.pageCount < 0) {
    throw new ValidationError("পাতা সংখ্যা ঋণাত্মক হতে পারে না", "pageCount");
  }
}

function handleFormSubmit(formData) {
  try {
    validateBookForm(formData);
    console.log("✅ ভ্যালিডেশন সফল, সেভ করা হচ্ছে...");
    // এখানে actual সেভ করার কোড থাকবে
  } catch (error) {
    if (error instanceof ValidationError) {
      const inputEl = document.getElementById(error.field);
      if (inputEl) {
        inputEl.style.border = "2px solid red";
      }
      alert(error.message);
    } else {
      console.error("অপ্রত্যাশিত এরর:", error);
    }
  } finally {
    console.log("ভ্যালিডেশন প্রক্রিয়া শেষ");
  }
}

handleFormSubmit({ title: "", author: "আরিফ" });
// "শিরোনাম আবশ্যক" alert দেখাবে, title ইনপুট লাল বর্ডার পাবে

নিজে চেষ্টা করো

Exercise:

  1. একটা AuthError কাস্টম ক্লাস বানাও (Error থেকে extend করে), যেটা লগইন ব্যর্থ হলে থ্রো হবে।
  2. উপরের validateBookForm ফাংশনে আরও একটা চেক যোগ করো — author নামে সংখ্যা থাকলে এরর দাও।
  3. error.cause ব্যবহার করে একটা এরর চেইন বানাও — যেমন "ফাইল আপলোড ব্যর্থ" এররের কারণ হিসেবে "নেটওয়ার্ক টাইমআউট" এরর দেখাও।
  4. একটা ফাংশনে finally ব্লক ব্যবহার করে টেস্ট করো এটা এরর হোক বা রিটার্ন হোক, দুই ক্ষেত্রেই রান হয় কিনা।

পরের পর্বে যা থাকছে

পরের পর্বে আমরা শিখব Module (import/export) — কীভাবে একটা বড় প্রজেক্টের কোড একাধিক ফাইলে ভাগ করে সংগঠিত রাখা যায়, আর সেগুলো একসাথে কীভাবে কাজ করে।

একটি মন্তব্য পোস্ট করুন

নবীনতর পূর্বতন

যোগাযোগ ফর্ম