المادة ، التي ننشر ترجمتها اليوم ، مخصصة لمعالجة أخطاء JS باستخدام
window.onerror
. هذا حدث خاص بالمتصفح يتم تشغيله عند حدوث أخطاء غير معروفة. سنتحدث هنا عن كيفية التقاط الأخطاء باستخدام
onerror
الأحداث
onerror
وكيفية إرسال معلومات عنها إلى خادم مطور موقع الويب. يمكن استخدام هذا المعالج كأساس لنظامك الخاص لجمع معلومات الخطأ وتحليلها. بالإضافة إلى ذلك ، فهي واحدة من أهم الآليات المستخدمة في المكتبات الموجهة للأخطاء ، مثل
raven-js .

الاستماع لحدث window.onerror
يمكنك الاستماع إلى حدث
onerror
خلال تعيين
window.onerror
وظيفة تلعب دور معالج الأخطاء:
window.onerror = function(msg, url, lineNo, columnNo, error) { // ... ... return false; }
يتم استدعاء هذه الوظيفة عند حدوث خطأ ، ويتم تمرير الوسيطات التالية إليها:
msg
- رسالة خطأ. على سبيل المثال ، Uncaught ReferenceError: foo is not defined
.url
- عنوان البرنامج النصي أو المستند الذي حدث فيه الخطأ. على سبيل المثال ، /dist/app.js
.lineNo
- رقم السطر الذي حدث الخطأ (إذا كان مدعومًا).- العمود رقم - رقم عمود الصف (إذا كان مدعومًا).
error
- كائن error
(إذا كان مدعومًا).
تخبر الوسيطات الأربعة الأولى المطور بأي نص ، وفي أي صف ، وفي أي عمود من هذا الصف حدث خطأ. قد تكون الوسيطة النهائية ، وهي كائن من نوع
Error
، هي الأكثر أهمية من بين جميع الحجج. لنتحدث عنه.
كائن خطأ وخاصية Error.prototype.stack
للوهلة الأولى ، لا يعتبر كائن
Error
خاصًا. يحتوي على ثلاث خصائص قياسية تمامًا -
message
و
fileName
و
lineNumber
. يمكن اعتبار هذه البيانات ، بالنظر إلى المعلومات التي تم تمريرها إلى معالج أحداث
window.onerror
، زائدة عن الحاجة.
القيمة الحقيقية في هذه الحالة هي الخاصية غير القياسية
Error.prototype.stack
. تتيح هذه الخاصية الوصول إلى مكدس الاستدعاءات (مكدس الأخطاء) ، ويسمح لك بمعرفة ما كان يحدث في البرنامج في وقت حدوث الخطأ ، والذي كان استدعاء الوظيفة يسبق ظهوره. يمكن أن يكون تتبع مكدس الاستدعاء جزءًا مهمًا من عملية تصحيح الأخطاء. وعلى الرغم من حقيقة أن خاصية
stack
ليست قياسية ، فهي متوفرة في جميع المتصفحات الحديثة.
هذا ما تبدو عليه خاصية
stack
كائن الخطأ في Chrome 46.
"Error: foobar\n at new bar (<anonymous>:241:11)\n at foo (<anonymous>:245:5)\n at <anonymous>:250:5\n at <anonymous>:251:3\n at <anonymous>:267:4\n at callFunction (<anonymous>:229:33)\n at <anonymous>:239:23\n at <anonymous>:240:3\n at Object.InjectedScript.\_evaluateOn (<anonymous>:875:140)\n at Object.InjectedScript.\_evaluateAndWrap (<anonymous>:808:34)"
أمامنا سلسلة غير منسقة. عندما يتم تقديم محتويات هذه الخاصية في هذا النموذج ، فمن غير المناسب العمل معها. إليك كيف سيبدو الشيء نفسه بعد التنسيق.
Error: foobar at new bar (<anonymous>:241:11) at foo (<anonymous>:245:5) at callFunction (<anonymous>:229:33) at Object.InjectedScript._evaluateOn (<anonymous>:875:140) at Object.InjectedScript._evaluateAndWrap (<anonymous>:808:34)
الآن ، بعد التنسيق ، تبدو مجموعة الأخطاء أكثر وضوحًا ، يصبح من الواضح على الفور سبب أهمية خاصية
stack
عند تصحيح الأخطاء.
ومع ذلك ، هنا كل شيء لا يسير بسلاسة. خاصية
stack
غير موحدة ؛ يتم تنفيذها بشكل مختلف في المتصفحات المختلفة. هنا ، على سبيل المثال ، هو ما يبدو مكدس الخطأ في Internet Explorer 11.
Error: foobar at bar (Unknown script code:2:5) at foo (Unknown script code:6:5) at Anonymous function (Unknown script code:11:5) at Anonymous function (Unknown script code:10:2) at Anonymous function (Unknown script code:1:73)
يمكنك أن ترى ، بالمقارنة مع المثال السابق ، أنه هنا لا يتم استخدام تنسيق مختلف فقط لتمثيل إطارات المكدس ، ولكن أيضًا هناك بيانات أقل لكل إطار. على سبيل المثال ، يحدد Chrome مثيلات استخدام الكلمة الرئيسية
new
ويوفر معلومات أكثر تفصيلاً حول الأحداث الأخرى (على وجه الخصوص ، حول استدعاءات الوظائف.
_evaluateOn
و.
_evaluateAndWrap
). في الوقت نفسه ، قارنا هنا فقط ما قدمه IE و Chrome. تستخدم المتصفحات الأخرى مناهجها الخاصة لعرض البيانات حول المكدس واختيار المعلومات المضمنة في هذه البيانات.
من أجل إضفاء مظهر موحد على كل هذا ، يمكنك استخدام أدوات الطرف الثالث. على سبيل المثال ، يستخدم raven-js TraceKit لهذا الغرض. Stacktrace.js وبعض المشاريع الأخرى تخدم نفس الغرض.
ميزات windows.onerror دعم المتصفحات المختلفة
حدث
windows.onerror
موجود في المتصفحات لبعض الوقت. على وجه الخصوص ، يمكن العثور عليه في IE6 و Firefox 2. المشكلة هنا هي أن جميع المتصفحات تنفذ
windows.onerror
بطرق مختلفة. على سبيل المثال ، يتعلق هذا بعدد وبنية الحجج التي تم تمريرها إلى معالجات هذا الحدث.
فيما يلي جدول
onerror
الحجج التي تم تمريرها إلى معالج
onerror
في المتصفحات الرئيسية.
متصفح
| الرسالة
| عنوان url
| السطر لا
| لا
| errorObj
|
فايرفوكس
| يوجد
| يوجد
| يوجد
| يوجد
| يوجد
|
كروم
| يوجد
| يوجد
| يوجد
| يوجد
| يوجد
|
الحافة
| يوجد
| يوجد
| يوجد
| يوجد
| يوجد
|
IE 11
| يوجد
| يوجد
| يوجد
| يوجد
| يوجد
|
IE10
| يوجد
| يوجد
| يوجد
| يوجد
| لا
|
IE 9.8
| يوجد
| يوجد
| يوجد
| لا
| لا
|
سفاري 10 وما فوق
| يوجد
| يوجد
| يوجد
| يوجد
| يوجد
|
سفاري 9
| يوجد
| يوجد
| يوجد
| يوجد
| لا
|
متصفح Android 4.4
| يوجد
| يوجد
| يوجد
| يوجد
| لا
|
ربما ليس من المستغرب أن Internet Explorer 8 و 9 و 10 لديهم دعم محدود
onerror
. ومع ذلك ، قد يبدو من غير المعتاد أنه في متصفح Safari لم يظهر دعم كائن الخطأ إلا في الإصدار العاشر ، الذي تم إصداره في عام 2016. بالإضافة إلى ذلك ، هناك أجهزة محمولة قديمة تستخدم متصفح Android القياسي ، والذي لا يدعم أيضًا كائن الخطأ. في الإصدارات الحديثة من Android ، تم استبدال هذا المتصفح بـ Chrome Mobile.
إذا لم يكن هناك كائن خطأ تحت تصرفنا ، فلن تكون هناك بيانات حول تتبع المكدس. هذا يعني أن المستعرضات التي لا تدعم كائن الخطأ لا توفر معلومات المكدس في البرنامج النصي القياسي لاستخدام معالج
onerror
. وهذا ، كما قلنا ، مهم للغاية.
تطوير Polyfill ل window.onerror باستخدام محاولة إنشاء / التقاط
للحصول على معلومات حول المكدس في المستعرضات التي لا تدعم تمرير كائن
onerror
إلى معالج
onerror
، يمكنك استخدام الحيلة التالية. يمكنك لف الكود في بنية
try/catch
والتقاط الأخطاء بنفسك. سيحتوي كائن الخطأ الناتج ، في جميع المتصفحات الحديثة ، على ما نحتاج إليه هو خاصية
stack
.
ألق نظرة على رمز أسلوب المساعد
invoke()
، الذي يستدعي الطريقة المحددة للكائن ، ويمررها مصفوفة من الوسيطات.
function invoke(obj, method, args) { return obj[method].apply(this,args); }
إليك كيفية استخدامه.
invoke(Math, 'max', [1,2])
هذا هو نفس الاستدعاء
invoke()
، ولكن الآن يتم استدعاء استدعاء الأسلوب في
try/catch
، مما يسمح لك بالتقاط الأخطاء المحتملة.
function invoke(obj, method, args) { try { return obj[method].apply(this,args); } catch(e) { captureError(e);// throw e;// } } invoke(Math,'highest',[1,2]); // , Math.highest
بالطبع ، من المكلف للغاية إضافة مثل هذه الهياكل يدويًا إلى جميع الأماكن التي قد تكون مطلوبة فيها. يمكن تبسيط هذه المهمة من خلال إنشاء وظيفة مساعد عالمية.
function wrapErrors(fn) { // if(!fn.__wrapped__) { fn.__wrapped__ = function() { try{ return fn.apply(this,arguments); }catch(e){ captureError(e);// throw e;// } }; } return fn.__wrapped__; } var invoke = wrapErrors(function(obj, method, args) { returnobj[method].apply(this,args); }); invoke(Math,'highest',[1,2]);//, Math.highest
نظرًا لأن جافا سكريبت تستخدم نموذج تنفيذ تعليمات برمجية أحادي السلسلة ، يجب استخدام هذا المجمّع فقط مع استدعاءات الوظائف الموجودة في بداية المكدسات الجديدة. ليست هناك حاجة لف جميع مكالمات الوظائف فيه.
ونتيجة لذلك ، اتضح أن هذه الوظيفة بحاجة إلى استخدامها في الأماكن التالية:
- مكان بدء التطبيق (على سبيل المثال ، عند استخدام jQuery ، في الوظيفة
$(document).ready
)) - في معالجات الأحداث (على سبيل المثال ، في
addEventListener
أو في إنشاءات النموذج $.fn.click
) - في عمليات الاستدعاء التي يتم استدعاؤها بواسطة أحداث المؤقت (على سبيل المثال ، يتم
setTimeout
أو requestAnimationFrame
)
فيما يلي مثال على استخدام وظيفة
wrapErrors
.
$(wrapErrors(function () {// doSynchronousStuff1();// setTimeout(wrapErrors(function () { doSynchronousStuff2();// })); $('.foo').click(wrapErrors(function () { doSynchronousStuff3();// })); }));
يمكن إضافة مثل هذه الإنشاءات إلى الرمز بنفسك ، ولكن هذه مهمة تستغرق وقتًا طويلاً. كبديل مناسب في مثل هذه المواقف ، يمكنك التفكير في المكتبات للتعامل مع الأخطاء ، والتي ، على سبيل المثال ، لديها آليات
addEventListener
و
setTimeout
أدوات
addEventListener
الأخطاء.
خطأ في النقل إلى الخادم
لذلك ، لدينا الآن وسائل تحت تصرفنا لاعتراض معلومات الخطأ إما باستخدام
windows.onerror
أو باستخدام الوظائف الإضافية بناءً على
try/catch
. تحدث هذه الأخطاء من جانب العميل ، وبعد اعتراضها ، نود أن نتعامل معها ونتخذ إجراءات للقضاء عليها. للقيام بذلك ، يجب أن يتم نقلهم إلى خادمنا. للقيام بذلك ، تحتاج إلى إعداد خدمة ويب تقبل معلومات الخطأ عبر HTTP ، ثم حفظها بطريقة أو بأخرى للمعالجة الإضافية ، على سبيل المثال ، ستكتب إلى ملف سجل أو قاعدة بيانات.
إذا كانت خدمة الويب هذه موجودة في نفس المجال مثل تطبيق الويب ، فستكون
XMLHttpRequest
كافية. يوضح المثال التالي كيفية استخدام دالة لتنفيذ استعلامات AJAX من jQuery لنقل البيانات إلى خادم.
function captureError(ex){ var errorData = { name:ex.name,// : ReferenceError message:ex.line,// : x is undefined url:document.location.href, stack:ex.stack// ; , ! }; $.post('/logger/js/',{ data:errorData }); }
ضع في اعتبارك أنه إذا كنت بحاجة إلى إرسال طلبات عبر النطاقات لإرسال معلومات حول الأخطاء إلى الخادم ، فسيتعين عليك رعاية دعم هذه الطلبات.
الملخص
لقد تعلمت أساسيات إنشاء خدمة للقبض على الأخطاء وإرسال معلومات عنها إلى الخادم. على وجه الخصوص ، قمنا هنا بفحص القضايا التالية:
- ميزات الحدث
onerror
ودعمه في المتصفحات المختلفة. - استخدام آلية
try/catch
للحصول على معلومات حول مكدس المكالمة في الحالات التي لا يدعم فيها onerror
العمل مع كائن الخطأ. - نقل بيانات الخطأ إلى خادم المطور.
بعد التعرف على كيفية عمل الآليات المذكورة أعلاه ، اكتسبت المعرفة الأساسية التي ستسمح لك ببدء إنشاء نظامك الخاص للتعامل مع الأخطاء ، وتوضيح التفاصيل الإضافية أثناء العمل. ربما يكون هذا السيناريو ملائمًا بشكل خاص لتلك الحالات عندما يتعلق الأمر بتطبيق معين حيث ، على سبيل المثال ، لأسباب أمنية ، لا يتم التخطيط لاستخدام مكتبات خارجية. إذا كان تطبيقك يسمح باستخدام رمز جهة خارجية ، يمكنك العثور على الأداة المناسبة لرصد أخطاء JS. ومن بين هذه الأدوات
Sentry و
Rollbar و
TrackJS ومشاريع أخرى مماثلة.
أعزائي القراء! ما أدوات مراقبة أخطاء JS التي تستخدمها؟
