بغض النظر عن مستوى مهاراتك ، فإن الأخطاء أو الاستثناءات هي جزء من حياة مطور التطبيق الخاص بك. يترك عدم الاتساق لتطوير الويب العديد من الأماكن التي يمكن أن تحدث فيها الأخطاء. مفتاح الحل هو التعامل مع أي أخطاء غير متوقعة (أو أخطاء متوقعة) للتحكم في تجربة المستخدم. مع JavaScript ، هناك مجموعة متنوعة من الميزات الفنية واللغوية التي يمكن استخدامها لحل أي مشكلة بشكل صحيح.
من الخطير التعامل مع الأخطاء في JavaScript. إذا كنت تؤمن بقانون ميرفي ، فإن ما الذي سيحدث سوف يحدث في النهاية! في هذه المقالة ، سوف أحفر في معالجة الأخطاء في JavaScript. سأشمل بعض المزالق والممارسات الجيدة. أخيرًا ، سنناقش معالجة الكود غير المتزامن و Ajax.
أعتقد أن نموذج JavaScript الذي يحركه الحدث يضيف معنى ثريًا لهذه اللغة. أعتقد أنه لا يوجد فرق بين المحرك الذي يحركه الحدث وآلية الإبلاغ عن الأخطاء لهذا النوع من المتصفح. كلما حدث خطأ ، فإنه يعادل رمي حدث في وقت معين. من الناحية النظرية ، يمكننا التعامل مع خطأ في رمي الأحداث في JavaScript مثلنا نتعامل مع الأحداث العادية. إذا كان هذا يبدو غريباً بالنسبة لك ، فركز على بدء الرحلة أدناه. هذه المقالة تستهدف JavaScript للعميل فقط.
مثال
يمكن الحصول على أمثلة الكود المستخدمة في هذه المقالة على جيثب. الصفحة الحالية تبدو هكذا:
النقر فوق كل زر سوف يرمي خطأ. يحاكي استثناء نوع typeerror. ما يلي هو تعريف واختبار الوحدة لمثل هذه الوحدة.
وظيفة خطأ () {var foo = {} ؛ إرجاع foo.bar () ؛}أولاً ، تحدد هذه الوظيفة كائن فارغ foo. لاحظ أن طريقة الشريط () غير محددة في أي مكان. نستخدم اختبارات الوحدة للتحقق من أن هذا يرمي خطأ.
it ('remrows a typeerror' ، function () {should.throws (target ، typeerror) ؛}) ؛يستخدم اختبار الوحدة هذا التأكيدات على اختبار المكتبات Mocha و wans.js. Mocha هو إطار اختبار قيد التشغيل ، ويجب أن يكون js مكتبة تأكيد. إذا لم تكن على دراية بهم ، فيمكنك تصفح مستنداتهم عبر الإنترنت مجانًا. عادةً ما تبدأ حالة الاختبار بها ("الوصف") وتنتهي بتمرير أو فشل التأكيد في. تتمثل ميزة استخدام هذا الإطار في أنه يمكن اختبار الوحدة في العقدة ، وليس في المتصفح. أقترح عليك إجراء هذه الاختبارات على محمل الجد لأنها تؤكد العديد من المفاهيم الأساسية الرئيسية في JavaScript.
كما هو موضح أعلاه ، يحدد Error () كائنًا فارغًا ثم يحاول استدعاء الطريقة فيه. نظرًا لأن طريقة الشريط () غير موجودة في هذا الكائن ، فسيقوم بإلقاء استثناء. ثق بي ، بلغات ديناميكية مثل JavaScript ، يمكن لأي شخص ارتكاب مثل هذه الأخطاء.
مظاهرة سيئة
دعنا نلقي نظرة على أساليب معالجة الأخطاء الضعيفة. سأقوم بتجريد الإجراء الخاطئ وأربطه بالزر. إليك ما يبدو عليه اختبار وحدة المعالج:
وظيفة badHandler (fn) {try {return fn () ؛ } catch (e) {} return null ؛}تتلقى وظيفة المعالجة هذه وظيفة رد الاتصال FN كاعتماد. ثم تسمى الوظيفة داخل المعالج. هذه الوحدة اختبار الأمثلة على كيفية استخدام هذه الطريقة.
IT ('إرجاع قيمة بدون أخطاء' ، function () {var fn = function () {return 1 ؛} ؛ var result = target (fn) ؛ النتيجة. يجب (النتيجة) .equal (null) ؛}) ؛كما ترون ، في حالة حدوث خطأ ، فإن هذه الطريقة الغريبة للتعامل معها تُرجع خالية. ستشير وظيفة رد الاتصال هذه إلى طريقة أو خطأ قانوني. يكمل حدث معالجة النقر أدناه الباقي.
(Function (Handler ، Bomb) {var badbutton = document.getElementById ('bad') ؛ if (badbutton) {badbutton.addeventListener ('click' ، function () {handler (bomb) ؛ console.log ('Imagine ، الحصول على تعزيز للاختباء') ؛}) ؛الشيء السيئ هو أن ما حصلت عليه للتو كان فارغًا. جعلني هذا مرتبكًا جدًا عندما كنت أفكر في تحديد الخطأ. تغطي استراتيجية الصمت هذه عند حدوث الأخطاء كل رابط من تصميم تجربة المستخدم إلى فساد البيانات. كان الجانب المحبط الذي تبعه أنه كان علي قضاء ساعات في تصحيح الأخطاء ولكن لم أستطع رؤية الخطأ في كتلة رمز المحاولة. تخفي هذه المعالجة الغريبة جميع الأخطاء في الكود ، ويفترض أن كل شيء طبيعي. يمكن تنفيذ ذلك بسلاسة في بعض الفرق التي لا تهتم بجودة الرمز. ومع ذلك ، فإن هذه الأخطاء المخفية ستجبرك في النهاية على قضاء ساعات في تصحيح الكود الخاص بك. في حل متعدد الطبقات يعتمد على مكدس الاتصال ، من الممكن تحديد من أين يأتي الخطأ. قد يكون من المناسب التعامل بصمت مع المحاولة في حالات نادرة. ولكن إذا واجهت خطأً ، فسوف تتعامل معه ، وهذا ليس حلاً جيدًا.
هذا الفشل-وهذا هو استراتيجية الصمت سوف يطالبك إلى التعامل بشكل أفضل مع الأخطاء في التعليمات البرمجية الخاصة بك. يوفر JavaScript طريقة أكثر أناقة للتعامل مع هذا النوع من المشكلات.
لا يمكن للقراءة
دعنا نستمر ، دعنا نلقي نظرة على النهج الذي يصعب فهمه. سوف أتخطى الجزء المقترن بإحكام مع DOM. هذا الجزء لا يختلف عن النهج السيئ الذي رأيناه للتو. ينصب التركيز على جزء اختبار الوحدة أدناه الذي يتعامل مع الاستثناءات.
وظيفة uglyHandler (fn) {try {return fn () ؛ } catch (e) {throw error ('خطأ جديد') ؛ }} it ('إرجاع خطأ جديد مع الأخطاء' ، function () {var fn = function () {رمي نوع جديد ('نوع خطأ') ؛} ؛ يجب.هناك تحسن جيد مقارنة بالعلاج السيئ الآن. يتم إلقاء الاستثناء في مكدس المكالمات. ما يعجبني هو أن الأخطاء يتم تحريرها من المكدس ، وهو أمر مفيد للغاية لتصحيح الأخطاء. عند إلقاء استثناء ، سينظر المترجم الفوري في وظيفة المعالجة التالية على مستوى في مكدس الاتصال. يوفر هذا العديد من الفرص للتعامل مع الأخطاء في المستوى الأعلى من مكدس المكالمات. لسوء الحظ ، لأنه خطأ صعب ، لا يمكنني رؤية معلومات الخطأ الأصلية. لذلك يجب أن أنظر على طول مكدس المكالمات وأجد الاستثناء الأكثر بدائية. لكن على الأقل أعلم أن هناك خطأ يحدث حيث يتم طرح الاستثناء.
على الرغم من أن هذا الخطأ غير القابل للقراءة غير قابل للقراءة غير ضار ، إلا أنه يجعل من الصعب فهم الكود. دعونا نرى كيف يتعامل المتصفح مع الأخطاء.
مكدس الاتصال
بعد ذلك ، تتمثل إحدى الطرق لرمي استثناء في إضافة محاولة ... Catch Code Block في المستوى العلوي من مكدس الاتصال. على سبيل المثال:
وظيفة main (bomb) {try {bomb () ؛ } catch (e) {// التعامل مع جميع الأشياء الخطأ}}ولكن ، تذكر أنني قلت أن المتصفحات مدفوعة بالحدث؟ نعم ، استثناء في JavaScript ليس أكثر من حدث. يوقف المترجم المترجم البرنامج في السياق الذي يحدث فيه الاستثناء حاليًا ويلقي استثناءً. لتأكيد ذلك ، ما يلي هو وظيفة معالجة الأحداث العالمية التي يمكننا رؤيتها. يبدو أن هذا:
window.adDeventListener ('error' ، function (e) {var error = e.error ؛ console.log (error) ؛}) ؛هذا معالج الحدث يمسك بالأخطاء في بيئة التنفيذ. ستنتج أحداث الخطأ أخطاء مختلفة في أماكن مختلفة. الهدف من هذا النهج هو التعامل مع الأخطاء مركزيا في الكود. تمامًا مثل الأحداث الأخرى ، يمكنك استخدام معالج عالمي للتعامل مع الأخطاء المختلفة. هذا يجعل الخطأ التعامل مع هدف واحد فقط إذا كنت تلتزم بمبادئ المسؤولية الصلبة ، والاستبدال المفتوح ، والاستبدال Liskov ، وفصل الواجهة وانعكاس التبعية). يمكنك تسجيل وظائف معالجة الأخطاء في أي وقت. ينفذ المترجم الحلقات هذه الحلقات. يتم تحرير الكود من البيانات المملوءة بالمحاولة ... الصيد ويصبح سهلاً للتصحيح. مفتاح هذا النهج هو التعامل مع الأخطاء التي تحدث تمامًا مثل أحداث JavaScript العادية.
الآن ، هناك طريقة لعرض مكدس الاتصال مع وظيفة المعالجة العالمية. ماذا يمكننا أن نفعل به؟ بعد كل شيء ، علينا استخدام مكدس الاتصال.
سجل مكدس المكالمات
مكدس المكالمات مفيد جدًا في معالجة إصلاحات الأخطاء. والخبر السار هو أن المتصفح يوفر هذه المعلومات. على الرغم من أن سمة المكدس لكائن الخطأ ليست قياسية في الوقت الحالي ، إلا أن هذه السمة مدعومة عمومًا في المتصفحات الأحدث.
لذا ، فإن الشيء الرائع الذي يمكننا القيام به هو طباعته على الخادم:
window.addeventListener ('error' ، function (e) {var stack = e.error.stack ؛ var message = e.error.toString () ؛ if (stack) {message + = '/n' + stack ؛} var xhr = new xmlhttprequest () ؛ xhr.open ('post' ، log '، true) ؛قد لا يكون الأمر واضحًا في مثال الكود ، ولكن سيتم تشغيل معالج الحدث هذا بواسطة رمز الخطأ السابق. كما ذكر أعلاه ، كل معالج له غرض واحد ، مما يجعل الكود جافًا (لا تكرر نفسك دون أن تصنع العجلة مرارًا وتكرارًا). ما يهمني هو كيفية التقاط هذه الرسائل على الخادم.
فيما يلي لقطة شاشة لوقت تشغيل العقدة:
مكدس المكالمات مفيد للغاية لتصحيح الرمز. لا تقلل أبدًا من دور مكدس المكالمة.
المعالجة غير المتزامنة
أوه ، من الخطير للغاية التعامل مع الكود غير المتزامن! JavaScript يجلب الكود غير المتزامن من بيئة التنفيذ الحالية. هذا يعني أن هناك مشكلة في Try ... بيان الصيد أدناه.
وظيفة Asynchandler (fn) {try {setTimeOut (function () {fn () ؛} ، 1) ؛ } catch (e) {}}لا يزال هناك جزء متبقي من اختبار الوحدة هذا:
IT ("لا يلتقط استثناءات مع الأخطاء" ، الدالة () {var fn = function () {رمي نوع جديد ('نوع خطأ') ؛} ؛ فشل (function () {target (fn) ؛}). }) ؛}لا بد لي من إنهاء هذا المعالج بوعد بالتحقق من الاستثناء. لاحظ أنه على الرغم من أن الكود الخاص بي هو كل شيء في المحاولة ، لا يزال هناك استثناء غير معقول. نعم ، جرب ... Catch يعمل فقط في بيئة تنفيذ منفصلة. عندما يتم طرح الاستثناء ، لم تعد بيئة تنفيذ المترجم المترجم هي كتلة المحاولة الحالية. يحدث هذا السلوك بشكل مشابه لمكالمات أياكس. لذلك ، هناك الآن خياران. البديل هو التقاط استثناءات في رد اتصال غير متزامن:
setTimeOut (function () {try {fn () ؛} catch (e) {// التعامل مع هذا الخطأ async}} ، 1) ؛على الرغم من أن هذه الطريقة مفيدة ، لا يزال هناك مجال كبير للتحسين. أولاً ، جرب ... تظهر كتل الرمز في كل مكان في الكود. في الواقع ، في السبعينيات من القرن الماضي ، أرادوا أن تراجع رمزهم. بالإضافة إلى ذلك ، يشجع محرك V8 استخدام Try ... كتل رمز الصيد في الوظائف (V8 هو محرك JavaScript الذي يستخدمه متصفح Chrome والعقدة). يوصيون بكتابة كتل الكود التي تجذب الاستثناءات في الجزء العلوي من مكدس الاتصال.
إذن ، ماذا يخبرنا هذا؟ كما قلت أعلاه ، من الضروري معالجات الأخطاء العالمية في أي سياق تنفيذ. إذا قمت بإضافة معالج خطأ إلى كائن نافذة ، فهذا هو ، لقد انتهيت! أليس من الجيد اتباع مبادئ الجافة والصلبة؟ سيحافظ معالج الأخطاء العالمي على الكود الخاص بك قابلة للقراءة ونظيفة.
فيما يلي التقرير المطبوع على معالجة استثناء من جانب الخادم. لاحظ أنه إذا كنت تستخدم الرمز في المثال ، فقد يختلف الإخراج قليلاً اعتمادًا على المتصفح الذي تستخدمه.
يمكن لهذا المعالج أن يخبرني أي خطأ يأتي من الكود غير المتزامن. يخبرني أن الخطأ يأتي من معالج setTimeOut (). رائع جدا!
الأخطاء هي جزء من كل تطبيق ، ولكن معالجة الأخطاء المناسبة ليست كذلك. هناك طريقتان على الأقل للتعامل مع الأخطاء. واحد هو حل الفشل ، الصمت ، أي ، تجاهل الأخطاء في الكود. هناك طريقة أخرى تتمثل في اكتشاف الأخطاء وحلها بسرعة ، أي التوقف عند الخطأ والتكاثر. أعتقد أنني عبرت بوضوح ما يعجبني ولماذا أحب ذلك. خياري: لا تخفي المشكلة. لن يلومك أحد على الأحداث غير المتوقعة في برنامجك. هذا أمر مقبول ، لكسر النقاط ، وإعادة إنتاج ، وإعطاء المستخدم تجربة. في عالم غير كامل ، من المهم أن تمنح نفسك فرصة. الأخطاء أمر لا مفر منه ، وما تفعله مهم لحل الخطأ. الاستخدام المعقول لميزات معالجة أخطاء JavaScript وفك التشفير التلقائي والمرن يمكن أن يجعل تجربة المستخدم أكثر سلاسة ، وكذلك تجعل تشخيص المطور أسهل.