آنلاین

خطاهای مدیریت‌نشده در Angular

هنگام اجرای برنامهٔ Angular، ممکن است بخشی از کد شما خطایی ایجاد کند. اگر این خطاها مدیریت نشوند، می‌توانند به رفتار غیرمنتظره و رابط کاربری بدون پاسخ منجر شوند. این راهنما توضیح می‌دهد Angular با خطاهایی که کد برنامهٔ شما صراحتاً آن‌ها را دریافت نکرده است چگونه برخورد می‌کند. برای راهنمایی دربارهٔ نوشتن منطق مدیریت خطا در برنامهٔ خود، به بهترین روش‌های مدیریت خطا در JavaScript و Angular مراجعه کنید.

یکی از اصول بنیادی راهبرد مدیریت خطا در Angular این است که هرجا ممکن باشد، خطاها باید در محل فراخوانی در معرض دید توسعه‌دهنده قرار بگیرند. این رویکرد تضمین می‌کند کدی که عملیاتی را آغاز کرده، زمینهٔ لازم برای درک و مدیریت درست خطا و تصمیم‌گیری دربارهٔ وضعیت مناسب برنامه را در اختیار داشته باشد. با نمایان‌شدن خطاها در مبدأ، توسعه‌دهندگان می‌توانند مدیریت خطایی متناسب با عملیات ناموفق پیاده‌سازی کنند که برای بازیابی یا ارائهٔ بازخوردی مفید به کاربر نهایی، به اطلاعات مرتبط دسترسی دارد. این کار همچنین از بوی بد «خطای بیش‌ازحد کلی» جلوگیری می‌کند؛ حالتی که خطاها بدون زمینهٔ کافی برای درک علتشان گزارش می‌شوند.

برای مثال، componentی را در نظر بگیرید که داده‌های کاربر را از یک API دریافت می‌کند. کدی که فراخوانی API را انجام می‌دهد باید مدیریت خطا را نیز دربر بگیرد (برای نمونه، با استفاده از بلوک try...catch یا عملگر catchError در RxJS) تا مشکلات احتمالی شبکه یا خطاهای بازگردانده‌شده از API را مدیریت کند. به این ترتیب، component می‌تواند پیام خطایی کاربرپسند نمایش دهد یا درخواست را دوباره امتحان کند، به‌جای آنکه اجازه دهد خطا بدون مدیریت منتشر شود.

خطاهای مدیریت‌نشده به ErrorHandler گزارش می‌شوند

Angular خطاهای مدیریت‌نشده را به ErrorHandler ریشهٔ برنامه گزارش می‌کند. هنگام ارائهٔ یک ErrorHandler سفارشی، آن را در زمان فراخوانی bootstrapApplication و درون ApplicationConfig خود فراهم کنید.

هنگام ساخت یک برنامهٔ Angular، اغلب کدی می‌نویسید که به‌طور خودکار توسط framework فراخوانی می‌شود. برای مثال، وقتی componentی در یک template ظاهر می‌شود، Angular مسئول فراخوانی constructor و متدهای lifecycle آن است. زمانی که framework کد شما را اجرا می‌کند، جای منطقی‌ای وجود ندارد که بتوانید برای مدیریت درست خطاها یک بلوک try اضافه کنید. در چنین موقعیت‌هایی، Angular خطاها را دریافت می‌کند و به ErrorHandler می‌فرستد.

Angular خطاهای درون APIهایی را که مستقیماً توسط کد شما فراخوانی می‌شوند دریافت نمی‌کند. برای مثال، اگر serviceای با متدی داشته باشید که خطا ایجاد می‌کند و آن متد را در component خود فراخوانی کنید، Angular آن خطا را به‌طور خودکار دریافت نخواهد کرد. مسئولیت مدیریت آن با سازوکارهایی مانند try...catch بر عهدهٔ شماست.

Angular خطاهای ناهمگام ناشی از promiseها یا observableهای کاربر را فقط زمانی دریافت می‌کند که:

  • قرارداد صریحی وجود داشته باشد که Angular باید منتظر عملیات ناهمگام بماند و از نتیجهٔ آن استفاده کند؛ و
  • خطاها در مقدار بازگشتی یا state ارائه نشده باشند.

برای مثال، AsyncPipe و PendingTasks.run خطاها را به ErrorHandler می‌فرستند، درحالی‌که resource خطا را در propertyهای status و error ارائه می‌کند.

خطاهایی که Angular به ErrorHandler گزارش می‌کند، خطاهای غیرمنتظره هستند. ممکن است این خطاها بازیابی‌ناپذیر باشند یا نشان دهند state برنامه خراب شده است. برنامه‌ها باید هرجا ممکن است در همان محل وقوع خطا، با استفاده از بلوک‌های try یا عملگرهای مناسب مدیریت خطا (مانند catchError در RxJS)، مدیریت خطا را انجام دهند؛ نه اینکه به ErrorHandler متکی باشند. کاربرد رایج و مناسب ErrorHandler صرفاً سازوکاری برای گزارش خطاهای احتمالاً مهلک به زیرساخت رهگیری و ثبت خطاست.

ts
export class GlobalErrorHandler implements ErrorHandler {
  private readonly analyticsService = inject(AnalyticsService);
  private readonly router = inject(Router);

  handleError(error: any) {
    const url = this.router.url;
    const errorMessage = error?.message ?? 'unknown';

    this.analyticsService.trackEvent({
      eventName: 'exception',
      description: `Screen: ${url} | ${errorMessage}`,
    });

    console.error(GlobalErrorHandler.name, {error});
  }
}

TestBed به‌طور پیش‌فرض خطاها را دوباره ایجاد می‌کند

در بسیاری از موارد، ممکن است ErrorHandler فقط خطاها را ثبت کند و در غیر این صورت اجازه دهد برنامه همچنان اجرا شود. بااین‌حال، در تست‌ها تقریباً همیشه می‌خواهید این خطاها آشکار شوند. TestBed در Angular خطاهای غیرمنتظره را دوباره ایجاد می‌کند تا خطاهایی که framework دریافت کرده، ناخواسته نادیده گرفته یا فراموش نشوند. در موارد نادر، ممکن است یک تست مشخصاً بخواهد اطمینان حاصل کند که خطاها باعث بی‌پاسخ‌شدن یا از کار افتادن برنامه نمی‌شوند. در این موقعیت‌ها می‌توانید با TestBed.configureTestingModule({rethrowApplicationErrors: false})، TestBed را طوری پیکربندی کنید که خطاهای برنامه را دوباره ایجاد نکند.

شنونده‌های سراسری خطا

خطاهایی که نه کد برنامه و نه instance برنامه در framework دریافت می‌کنند، ممکن است به scope سراسری برسند. اگر خطاهای رسیده به scope سراسری در نظر گرفته نشوند، می‌توانند پیامدهای ناخواسته‌ای داشته باشند. در محیط‌های غیرمرورگری ممکن است باعث از کار افتادن process شوند. در مرورگر ممکن است این خطاها گزارش نشوند و بازدیدکنندگان سایت فقط آن‌ها را در console مرورگر ببینند. Angular برای رسیدگی به این مشکلات، در هر دو محیط شنونده‌های سراسری فراهم می‌کند.

رندر سمت client

افزودن provideBrowserGlobalErrorListeners() به ApplicationConfig، listenerهای 'error' و 'unhandledrejection' را به window مرورگر اضافه می‌کند و این خطاها را به ErrorHandler می‌فرستد. Angular CLI به‌طور پیش‌فرض برنامه‌های جدید را با این provider تولید می‌کند. تیم Angular توصیه می‌کند بیشتر برنامه‌ها این خطاهای سراسری را، چه با listenerهای داخلی framework و چه با listenerهای سفارشی خودشان، مدیریت کنند. اگر listenerهای سفارشی ارائه می‌دهید، می‌توانید provideBrowserGlobalErrorListeners را حذف کنید.

رندر سمت server و ترکیبی

هنگام استفاده از Angular همراه با SSR، Angular به‌طور خودکار listenerهای 'unhandledRejection' و 'uncaughtException' را به process سرور اضافه می‌کند. این handlerها از از کار افتادن سرور جلوگیری می‌کنند و در عوض، خطاهای دریافت‌شده را در console ثبت می‌کنند.

مهم: اگر برنامه از Zone.js استفاده کند، فقط handler مربوط به 'unhandledRejection' اضافه می‌شود. در حضور Zone.js، خطاهای داخل Zone برنامه از قبل به ErrorHandler برنامه فرستاده می‌شوند و به process سرور نمی‌رسند.