معالجة الأخطاء في لغة JavaScript


معالجة الأخطاء في لغة JavaScript

يا هلا بالجميع! لما تكتب كود، الأخطاء حتمية. مو مشكلة، كلنا نغلط! الأهم إنك تعرف كيف تتعامل معاها عشان تطبيقك ما ينهار فجأة ويخلي المستخدمين في حيرة. هنا بنشوف كيف JavaScript بتساعدنا نعالج الأخطاء بطريقة احترافية.

ليش نحتاج معالجة الأخطاء؟

ببساطة، عشان تطبيقك يكون قوي وموثوق. تخيل المستخدم يحاول يسوي شيء، ويطلع له خطأ يوقف كل شيء! هذا مو كويس أبدًا. معالجة الأخطاء بتخليك تتوقع المشاكل المحتملة وتوفر حلول بديلة، أو على الأقل، تعرض رسالة واضحة للمستخدم بدل شاشة بيضاء أو خطأ غامض.

الأساس: try...catch

هذي هي الأداة الأساسية لمعالجة الأخطاء في JavaScript. الفكرة بسيطة:

  • الجزء اللي تتوقع ممكن يطلع فيه خطأ تحطه داخل try.
  • لو صار خطأ داخل try، الكود اللي داخل catch بيشتغل عشان يعالج الخطأ.

شوف المثال:

المتغير x مو معرف، فالجزء اللي داخل try بيطلع خطأ. الكود بينتقل لـ catch عشان يتعامل مع الخطأ.


try {
    let result = x / 2; // 'x' is not defined, this will throw an error
    console.log(result);
} catch (error) {
    console.error("أوه! حدث خطأ:", error.message);
    // هنا ممكن تعرض رسالة للمستخدم أو تسجل الخطأ
}
console.log("البرنامج استمر في العمل بعد معالجة الخطأ.");

المتغير error اللي يجي مع catch هو كائن (object) فيه تفاصيل عن الخطأ، مثل error.name (نوع الخطأ) و error.message (رسالة الخطأ).

الـ finally بلوك: دائمًا يُنفذ

فيه جزء ثالث ممكن تضيفه لـ try...catch وهو finally. الكود اللي داخله بيتنفذ دايماً، سواء صار خطأ أو ما صار. مفيد جدًا لو عندك موارد لازم تقفلها أو تنظفها بعد ما تخلص عملية معينة.


try {
    console.log("بدء العملية...");
    // let y = 10 / 0; // هذا ما يعتبر خطأ في JavaScript (يطلع Infinity)
    let obj = null;
    console.log(obj.property); // هذا بيطلع TypeError
    console.log("العملية تمت بنجاح.");
} catch (error) {
    console.error("حدث خطأ في try:", error.message);
} finally {
    console.log("هذا الكود يتنفذ دائمًا (تنظيف، إغلاق اتصالات، إلخ).");
}
console.log("البرنامج استمر.");

رمي الأخطاء بنفسك: throw

أحيانًا، أنت اللي تحدد متى يعتبر شيء خطأ. مثلاً، لو دالة تتوقع مدخل معين وما جاء، ممكن ترمي خطأ بنفسك عشان اللي يستخدم الدالة يعرف إن فيه مشكلة.

تقدر ترمي أي شيء كخطأ، لكن الأفضل إنك ترمي كائن Error أو واحد من مشتقاته (مثل TypeError، RangeError).


function checkAge(age) {
    if (age < 0 || age > 120) {
        throw new RangeError("العمر يجب أن يكون بين 0 و 120.");
    }
    console.log("العمر مقبول:", age);
}

try {
    checkAge(150); // هذا بيرمي خطأ
} catch (error) {
    if (error instanceof RangeError) {
        console.warn("تحذير: خطأ في نطاق العمر:", error.message);
    } else {
        console.error("خطأ غير متوقع:", error.message);
    }
}

try {
    checkAge(30); // هذا بيشتغل تمام
} catch (error) {
    console.error("هذا ما المفروض يصير هنا:", error.message);
}

استخدام throw new Error("رسالة الخطأ") هو الأسلوب المفضل لرمي الأخطاء المعيارية.

أنواع الأخطاء الشائعة

JavaScript عندها أنواع أخطاء مدمجة بتفيدك تعرف وش صار بالضبط:

  • ReferenceError: لما تحاول تستخدم متغير ما هو معرف.
  • TypeError: لما تحاول تسوي عملية غير صالحة على نوع معين (مثل استدعاء دالة على شيء مو دالة).
  • SyntaxError: لما يكون فيه خطأ في كتابة الكود نفسه (غالباً ما تتلحق بـ try...catch).
  • RangeError: لما قيمة رقمية تكون خارج النطاق المسموح به.
  • URIError: أخطاء تتعلق بالدوال اللي تتعامل مع عناوين الـ URI (مثل decodeURI).

معالجة الأخطاء في الكود غير المتزامن (Asynchronous Code)

هنا الوضع يختلف شوي، try...catch العادي ما بيشتغل مع الأخطاء اللي تصير في callbacks أو Promises إلا بطرق معينة.

مع Promises: .catch()

الـ Promises عندها طريقة خاصة لمعالجة الأخطاء عن طريق الدالة catch(). أي خطأ يصير داخل Promise (سواء كان throw أو خطأ تلقائي) بيتم التقاطه بواسطة أقرب .catch().


function fetchData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const success = false; // خلينا نفترض صار خطأ
            if (success) {
                resolve("تم جلب البيانات بنجاح!");
            } else {
                reject(new Error("فشل في جلب البيانات من الخادم."));
            }
        }, 1000);
    });
}

fetchData()
    .then(data => console.log(data))
    .catch(error => console.error("خطأ في Promise:", error.message));

مع async/await

هنا الخبر الحلو! async/await تخلينا نستخدم try...catch بشكل عادي كأننا نتعامل مع كود متزامن، وهذا يبسط الأمور كثير.


async function processData() {
    try {
        const response = await fetchData(); // 'fetchData' هي نفس الدالة اللي فوق
        console.log(response);
    } catch (error) {
        console.error("خطأ في async/await:", error.message);
    } finally {
        console.log("تمت محاولة معالجة البيانات.");
    }
}

processData();

نصائح سريعة لمعالجة الأخطاء

  • لا تبتلع الأخطاء: لا تحط try...catch وتخلي catch فاضي! هذا بيخليك ما تدري وش يصير. على الأقل، سجل الخطأ في الـ console.
  • كن محددًا: حاول تعالج الأخطاء اللي تتوقعها فقط. لا تحط كود كبير جدًا داخل try وتتوقع إن catch بيحل كل شيء.
  • قدم رسائل واضحة: سواء للمستخدم أو للمطورين (في الـ logs)، الرسالة الواضحة بتوفر عليك وقت كثير.
  • استخدم أدوات التسجيل (Logging Tools): في التطبيقات الكبيرة، استخدم مكتبات أو خدمات لتسجيل الأخطاء عشان تقدر تراجعها وتصلحها.

وبس! هذا كان ملخص سريع ومباشر عن معالجة الأخطاء في JavaScript. طبقها عشان كودك يكون أقوى وأكثر احترافية.