مقدمه

در درس قبل با مکانیزم فنی گرفتن خطا با استفاده از try...catch آشنا شدیم. اما گرفتن خطا تنها قدم اول است. یک مهندس نرم‌افزار حرفه‌ای باید بداند که پس از گرفتن خطا، چه کاری باید انجام دهد. داشتن یک استراتژی مشخص برای مدیریت خطاها، تفاوت بین یک اپلیکیشن شکننده و یک اپلیکیشن قوی و قابل اعتماد را رقم می‌زند. در این درس، الگوها و استراتژی‌های مختلف برای واکنش به خطاها را بررسی می‌کنیم.

مدیریت محلی در مقابل مدیریت متمرکز

یکی از اولین تصمیماتی که باید بگیریم این است که خطا را در همان جایی که رخ می‌دهد مدیریت کنیم یا اجازه دهیم به سطح بالاتری از برنامه منتقل شود.

مدیریت خطای محلی (Local Handling)

در این رویکرد، خطا را دقیقاً در همان بلوک catch که آن را گرفته‌ایم، مدیریت می‌کنیم. این استراتژی برای خطاهای قابل پیش‌بینی که راه حل یا جایگزین مشخصی دارند، بسیار مناسب است. برای مثال، اگر تصویر پروفایل کاربر بارگذاری نشود، می‌توانیم یک تصویر پیش‌فرض را به جای آن نمایش دهیم.

Copy Icon JAVASCRIPT
async function displayUserProfile() {
    try {
        const user = await fetchUserData();
        renderUser(user);
    } catch (error) {
        // Graceful fallback: If fetching fails, show a default state.
        console.warn('Could not fetch user, showing guest profile.');
        renderGuestProfile();
    }
}

در این کد، تابع displayUserProfile می‌داند که اگر دریافت اطلاعات کاربر با خطا مواجه شد، باید یک پروفایل مهمان را نمایش دهد. خطا در همین سطح مدیریت شده و از انتشار آن به سایر بخش‌های برنامه جلوگیری می‌شود.

مدیریت خطای متمرکز (Centralized Handling)

برای خطاهای غیرمنتظره یا بحرانی که راه حل مشخصی در سطح محلی ندارند، بهتر است اجازه دهیم خطا به سطوح بالاتر برنامه "حباب" کند تا توسط یک مدیر خطای عمومی و متمرکز گرفته شود. این مدیر متمرکز می‌تواند به عنوان یک «تور ایمنی» (safety net) عمل کند.

یک راه ساده برای پیاده‌سازی این الگو، استفاده از رویداد سراسری window.onerror است. این شنونده هر خطایی را که در هیچ بلوک catch مدیریت نشده باشد، دریافت می‌کند.

Copy Icon JAVASCRIPT
window.onerror = function(message, source, lineno, colno, error) {
    console.error('An uncaught error occurred!');
    
    // In a real application, send the error details to a logging service
    // logErrorToServer({ message, source, lineno, colno, stack: error.stack });
    
    // Optional: Show a generic error message to the user
    showGenericErrorUI();

    return true; // Prevents the default browser error message in the console
};

// A function somewhere else that might fail unexpectedly
function doSomethingRisky() {
    throw new Error('A critical system failed!');
}

doSomethingRisky(); // This error will be caught by window.onerror

در اینجا، هر خطای مدیریت‌نشده‌ای در برنامه، توسط window.onerror گرفته می‌شود. این مکان ایده‌آلی برای ارسال جزئیات خطا به سرور (برای تحلیل تیم توسعه) و نمایش یک پیام عمومی به کاربر است.

استراتژی‌های کلیدی دیگر

علاوه بر انتخاب بین مدیریت محلی و متمرکز، چندین استراتژی دیگر نیز برای بهبود فرآیند مدیریت خطا وجود دارد.

گزارش و ثبت خطا (Logging)

استفاده از console.error برای محیط توسعه عالی است، اما در محیط پروداکشن هیچ ارزشی ندارد. خطاهایی که برای کاربران واقعی رخ می‌دهد باید به یک سرویس گزارش‌دهی خطا (مانند Sentry، LogRocket یا Datadog) ارسال شود. این کار به تیم توسعه اجازه می‌دهد تا از بروز باگ‌ها مطلع شده، آنها را ردیابی و به سرعت رفع کنند.

ارائه بازخورد به کاربر

هرگز نباید پیام‌های خطای فنی و خام را به کاربر نمایش دهید. یک پیام مانند "TypeError: Cannot read properties of null" برای کاربر بی‌معنی و ترسناک است. به جای آن، یک پیام عمومی، آرامش‌بخش و کاربرپسند نمایش دهید، مانند: «متأسفانه خطایی رخ داده است. تیم ما مطلع شده و در حال بررسی است. لطفاً لحظاتی دیگر دوباره تلاش کنید.»

مکانیزم تلاش مجدد (Retry Mechanism)

بسیاری از خطاها، به ویژه خطاهای شبکه، ماهیت موقتی دارند. در چنین مواردی، تلاش مجدد برای انجام عملیات می‌تواند یک راه حل مؤثر باشد. یک الگوی پیشرفته‌تر در این زمینه، «عقب‌نشینی نمایی» (Exponential Backoff) است که در آن فاصله زمانی بین هر تلاش مجدد به صورت نمایی افزایش می‌یابد تا از وارد کردن فشار بیش از حد به یک سرور که در حال حاضر با مشکل مواجه است، جلوگیری شود.

در این درس با استراتژی‌های مختلفی برای مدیریت هوشمندانه خطاها آشنا شدیم. دیدیم که یک برنامه خوب نه تنها خطاها را می‌گیرد، بلکه بر اساس نوع و زمینه خطا، به شیوه‌ای معنادار به آنها واکنش نشان می‌دهد؛ چه با ارائه یک جایگزین، چه با ثبت خطا برای تیم توسعه، و چه با نمایش یک پیام مناسب به کاربر. اما قبل از اینکه بتوانیم خطایی را مدیریت کنیم، باید آن را پیدا کنیم. در درس بعدی، «تکنیک‌های دیباگ»، با ابزارها و روش‌های عملی برای پیدا کردن و رفع باگ‌ها در کدهای جاوااسکریپت آشنا خواهیم شد.