Mohammad Jawad Barati
Mohammad Jawad Barati
خواندن ۶ دقیقه·۴ سال پیش

بحث شیرین ارور هندلینگ تو نود.جی‌اس


یه نکته قبل از شروع : ارور های پایان کار نیستن. بلکه تازه باید راه های جدید رو تست کرد و شاید با اندکی ور رفتن راه باز شد. پس تنها وظیفه شما هندل کردن درست این ارور هاست.
یه نکته قبل از شروع : ارور های پایان کار نیستن. بلکه تازه باید راه های جدید رو تست کرد و شاید با اندکی ور رفتن راه باز شد. پس تنها وظیفه شما هندل کردن درست این ارور هاست.

شما توی برنامه با ۳ دسته ارور روبرو میشید:

  1. ارور های تکنیکال یا اونایی که مربوط به شبکه هستن: مثلا دیتابیس خاموشه. تو این مورد ها میتونید به یوزر بگید که یه مشکلی سمت سرور هست که فعلا جواب نمیتونیم بهت بدیم. لطفا صبر کن. بعدش هم به ادمین یه ایمیل بزنید که بیاد مشکلو حل بکنه
  2. ارور های که معمولا رخ میدن: مثلا وقتی داری تو دیتابیس یه رکورد اضافه می‌کنی ممکنه بنا به هر دلیلی ارور بده دیتابیس. تو این موردا بهترین کار این شاید باشه که به کاربر اجازه بدی دوباره تلاش بکنه. یا وقتی کاربر میخواد ثبت نام بکنه ولی شماره تلفنش مجاز نیست.
  3. ارور هایی که هنگام اجرای برنامه تون رخ میده و ارور های logical بهش میگیم. یعنی مشکل از سمت کاربر نیست. بلکه کدی که ما زدیم مشکل داشته. پس این ارور ها رو باید تو پروسه توسعه برنامه حل بکنیم.

ارور هایی که throw میشن ارور هایی دسته ۱ و ۳ هستن. تو این موقع میتونیم از try catch یا then catch استفاده بکنیم و در نهایت یا ارور ها رو مستقیما هندل میکنیم یا که از یه میدلویر برای هندل کردن ارور ها استفاده می‌کنیم.

و ارور هایی که throw نمیشن ارور های دسته ۲ هستن. مثلا کاربر ایمیل مجاز وارد نکرده، تو این حالت دو گزینه روی میز هست: اولیش اینه که یه ارور throw کنی و مسیر بالا رو طی کنی، دومین گزینه‌ی روی میز اینه که بیای ارور رو هندل بکنی. فرضا اجازه‌ی ثبت نام بدی ولی به کاربر بگی که باید ایمیلتو درست بکنی.

آخرین مرحله نشون دادن ارور به کاربر هست. این مرحله ۳ روش پیاده سازی متفاوت داره:

  1. کاربرو به صفحه معروف ۵۰۰ ریدایرکت کنی و بهش ارور رو نشون بدی (مثلا زمانی که کاربر یه درخواستی ارسال کرده سمت سرور ولی یه باگ یا ... باعث شده سرور نتونه جواب بده)
  2. کاربرو به صفحه ای که بود برگردونی و بهش ارور رو نشون بدی (مثلا کاربر میخواسته اطلاعات شخصیشو ویرایش بکنه ولی شماره تلفنش رو اشتباه وارد کرده)
  3. کاربر رو ریدایرکت کنی به صفحه ای که توش بود (مثلا کاربر لاگین نکرده و به یه route ای که protected هست درخواست ارسال کرده)

وقتی یه ارور throw میشه جاوااسکریپت میاد اجرای برنامه رو متوقف میکنه و دنبال یه بلاک catch میگرده. فرض کن تو یه میدلویر اومدی تابع A رو call کردی و بعد تو تابع A تابع B رو call کردی. وقتی ارور تو تابع B رخ بده میاد با استفاده از call stack بر میگرده عقب تا به یه catch برسه.

اگر نرسه پروسه برنامه بسته میشه و ارور مشهور UnhandledPromiseRejection رو میبینید، در صورتی که promise بیس باشه و اگر هم callback باشه ارور رو تو کامند لاین میبینید.


ارور throw کردن تو callback ها

وقتی میای همچین کاری میکنی چه انتظاری از جاوااسکریپت داری؟

try { fs.readFile('this-file-does-not-exist', function(error, data) { if (error) throw error; else console.log(data); }); } catch (error) { console.error(error); };

شاید تنها چیزی که انتظارش رو نداشته باشی این باشه که پروسه برنامه بسته بشه و بهت بگه همچین فایلی وجود نداره. چرا این کار رو میکنه؟ دلیلش خیلی ساده هست. وقتی شما این کد رو اجرا می‌کنی اول کدت کامپایل میشه و بعدش اجرا.

وقتی کدت داره اجرا میشه یه callback رو میاد تو callback queue قرار میده. هر وقت فایل سیستم نتیجه رو (چه ارور، چه محتوای فایل) برگردوند اون callback میاد اجرا میشه. ولی الان جاوااسکریپت try catch رو اجرا کرده و از روش رد شده. به همین خاطر دیگه try catch ای وجود نداره برای fs.readFile. پس ارور باعث بسته شدن برنامه میشه.

راه حل اینه که بیایم اون callback رو که error first هست به promise تبدیل بکنیم. برای این منظور میتونیم از کتابخونه ها یا از آبجکت Promise خود جاوااسکریپت استفاده بکنیم.

const { promisify } = require('util'); const fsReadFile = promisify(fs.readFile); async function A() { try { let data = await fs.readFile('this-file-does-not-exist'); console.log(data); } catch (error) { console.error(error); }; };

یا که بیای

function readFileAsync (filePath) { return new Promise(function (resolve, reject) { fs.readFile(filePath, function (error, data) { if (error) reject(error); else resolve(data); }); }); }; async function A() { try { let data = await fs.readFile('this-file-does-not-exist'); console.log(data); } catch (error) { console.error(error); }; };

حالا شما همین مثال ساده رو تعمیم بده به مورد استفاده خودت.

مفهوم call stack

اول main اجرا میشه. بعدش doJob صدا زده میشه. بعدش printLog فراخوانی میشه و اخر سر هم console.log صدا زده شده. پس اول console.log اجراش باید تموم بشه. بعدش printLog و ...
اول main اجرا میشه. بعدش doJob صدا زده میشه. بعدش printLog فراخوانی میشه و اخر سر هم console.log صدا زده شده. پس اول console.log اجراش باید تموم بشه. بعدش printLog و ...

خب در مرحله بعد میرسیم به اینکه حالا این ارور ها رو هندل کردیم ولی اگه یه موقع ارور UnhandledPromiseRejection داد چکار بکنم. جوابش اینه:

process.on('unhandledRejection', error => { // Prints &quotunhandledRejection woops!&quot console.log('unhandledRejection', error.test); });

یا اگر داری وب اپ مینویسی میتونی همون دستورای بالا رو تو میدلویری که برای هندل کردن ارور های ۵۰۰ ساختی بزاری و بعدش وقتی اروری رخ داد که تو اصلا هندلش نکرده بودی صفحه ۵۰۰ رو به کاربر نشون بدی.


بحث لاگ

حالا که فهمیدی داستان تو این بخش ها چیه تازه اول راه هستی و قدم بعدیت این میتونه باشه که لاگ ها رو چکار بکنی. این مقاله رو بخون

error handlingnode js
برنانه نویس، مدرس، محقق. عاشق انیمه هستم و دنبال چالش ها جدید.
شاید از این پست‌ها خوشتان بیاید