يعرف جميع المهندسين في الواجهة الأمامية أن JavaScript لديها قدرات معالجة الاستثناءات الأساسية. يمكننا رمي خطأ جديد () ، وسيقوم المتصفح أيضًا بإلقاء استثناء عندما نسمي خطأ API. ولكن من المقدر أن معظم المهندسين الأماميين لم يفكروا أبدًا في جمع معلومات الاستثناء هذه
على أي حال ، طالما فشل التحديث في التكاثر بعد خطأ JavaScript ، يمكن للمستخدم حل المشكلة عن طريق التحديث ، ولن يعطل المتصفح ، وسيكون على ما يرام إذا لم يحدث. كان هذا الافتراض صحيحًا قبل أن يصبح تطبيق الصفحة الواحدة شائعة. تطبيق الصفحة الفردية الحالية معقد للغاية بعد الركض لفترة من الزمن. ربما قام المستخدمون بإجراء العديد من عمليات الإدخال قبل وصولهم إلى هنا. كيف يمكنهم تحديث إذا قالوا إنهم يريدون؟ ألن تقوم بإعادة صياغة العمليات السابقة تمامًا؟ لذلك لا يزال من الضروري بالنسبة لنا التقاط معلومات الاستثناء هذه وتحليلها ، ثم يمكننا تعديل الكود لتجنب التأثير على تجربة المستخدم.
كيفية التقاط الاستثناءات
كتبنا أنفسنا نرمي خطأ جديد (). إذا أردنا التقاط ، يمكننا بالتأكيد التقاطه لأننا نعرف جيدًا أين تتم كتابة الرمي. ومع ذلك ، فإن الاستثناءات التي تحدث عند استدعاء API للمتصفح ليست من السهل بالضرورة الصيد. تقول بعض واجهات برمجة التطبيقات إنه سيتم إلقاء الاستثناءات في المعيار ، وبعض واجهات برمجة التطبيقات فقط لها متصفحات فردية ترمي استثناءات بسبب اختلافات التنفيذ أو العيوب. بالنسبة إلى الأول ، يمكننا أيضًا التقاطها من خلال Try-Catch ، وللأخير ، يجب أن نستمع إلى استثناءات عالمية ثم التمسك بها.
تجرب
إذا كان من المعروف أن بعض واجهات برمجة تطبيقات المتصفح ترمي الاستثناءات ، فنحن بحاجة إلى وضع المكالمة في Try-Catch لتجنب البرنامج بأكمله الذي يدخل دولة غير قانونية بسبب الأخطاء. على سبيل المثال ، Window.localStorage هو واجهة برمجة التطبيقات. سيتم طرح استثناء بعد كتابة البيانات يتجاوز حد السعة ، وسيكون هذا صحيحًا أيضًا في وضع التصفح الخاص في Safari.
نسخة الكود كما يلي:
يحاول {
localstorage.setitem ('date' ، date.now ()) ؛
} catch (خطأ) {
المراسل (خطأ) ؛
}
سيناريو آخر مشترك للمحاولة هو عمليات الاسترجاعات. نظرًا لأن رمز وظيفة رد الاتصال أمر لا يمكن السيطرة عليه ، فإننا لا نعرف مدى جودة الكود ، وما إذا كان سيتم استدعاء واجهات برمجة التطبيقات الأخرى التي ترمي الاستثناءات. لكي لا تتسبب في تنفيذ رموز أخرى بعد استدعاء رد الاتصال بسبب أخطاء رد الاتصال ، من الضروري إعادة الاتصال إلى المحاولة.
نسخة الكود كما يلي:
المستمعين. foreach (وظيفة (مستمع) {
يحاول {
المستمع () ؛
} catch (خطأ) {
المراسل (خطأ) ؛
}
}) ؛
window.onerror
بالنسبة للأماكن التي لا يمكن تغطيتها ، في حالة حدوث استثناء ، لا يمكن التقاطها إلا من خلال window.onerror.
نسخة الكود كما يلي:
window.onerror =
دالة (errormessage ، scripturi ، الكتان) {
المراسل ({
الرسالة: errormessage ،
السيناريو: Scripturi ،
الخط: عدد الكتان
}) ؛
}
احرص على عدم أن تكون ذكيًا واستخدم Window.AdDeventListener أو Window.attachevent للاستماع إلى Window.onerror. العديد من المتصفحات تنفذ فقط window.onerror ، أو فقط تنفيذ window.onerror هو قياسي. بالنظر إلى أن المسودة القياسية تحدد أيضًا window.oneror ، نحتاج فقط إلى استخدام Window.Orror.
الممتلكات المفقودة
لنفترض أن لدينا وظيفة مراسل لجمع استثناءات تم صيدها ثم إرسالها على دفعات إلى تخزين من جانب الخادم للاستعلام والتحليل ، ما هي المعلومات التي نريد جمعها؟ تتضمن المزيد من المعلومات المفيدة: نوع الخطأ (الاسم) ، رسالة خطأ (رسالة) ، عنوان ملف البرنامج النصي (البرنامج النصي) ، رقم السطر (السطر) ، رقم العمود (العمود) ، وتتبع المكدس. إذا تم اكتشاف استثناء من خلال المحاولة ، فإن كل هذه المعلومات موجودة على كائن الخطأ (بدعم من المتصفحات السائدة) ، بحيث يمكن لـ Resporterror أيضًا جمع هذه المعلومات. ولكن إذا تم التقاطها من خلال window.onerror ، نعلم جميعًا أن وظيفة الحدث هذه لديها 3 معلمات فقط ، وبالتالي فقدت المعلومات غير المتوقعة لهذه المعلمات الثلاثة.
تسلسل الرسائل
إذا تم إنشاء كائن الخطأ من قبل أنفسنا ، فسيتم التحكم في error.message من قبلنا. في الأساس ، ما نضعه في error.message ، وما سيكون المعلمة الأولى (رسالة) من window.onerror. (سيقوم المتصفح في الواقع بإجراء تعديلات طفيفة ، مثل إضافة "الخطأ غير المطلوب:" بادئة.) لذلك ، يمكننا تسلسل السمات التي نشعر بالقلق (مثل json.stringify) وتخزينها في خطأ. بالطبع ، يقتصر هذا على كائن الخطأ الذي أنشأناه بأنفسنا.
المعلمة الخامسة
يعرف مصنعو المتصفح أيضًا القيود التي يخضع لها الأشخاص عند استخدام Window.Orror ، بحيث يبدأون في إضافة معلمات جديدة إلى Window.onerror. بالنظر إلى أن أرقام الصفوف فقط وعدم وجود أرقام أعمدة تبدو متناظرة للغاية ، أي إضافة أرقام الأعمدة أولاً ووضعها في المعلمة الرابعة. ومع ذلك ، فإن ما يقلقه الجميع أكثر هو ما إذا كان بإمكانهم الحصول على المكدس الكامل ، لذلك قال Firefox إنه سيكون من الأفضل وضع المكدس في المعلمة الخامسة. لكن Chrome قال إنه سيكون من الأفضل وضع كائن الخطأ بأكمله في المعلمة الخامسة. أي سمة تريد قراءتها ، بما في ذلك السمات المخصصة. نتيجة لذلك ، نظرًا لأن Chrome أسرع ، تم تنفيذ نافذة جديدة.
نسخة الكود كما يلي:
window.onerror = وظيفة (
errormessage ،
scripturi ،
عدد الكتان ،
عدد الأعمدة ،
خطأ
) {
إذا (خطأ) {
المراسل (خطأ) ؛
} آخر {
المراسل ({
الرسالة: errormessage ،
السيناريو: Scripturi ،
الخط: عدد الكتان ،
العمود: عدد العمود
}) ؛
}
}
انتظام السمات
تستند أسماء خصائص كائن الخطأ التي ناقشناها من قبل إلى طرق تسمية الكروم. ومع ذلك ، تسمية المتصفحات المختلفة خصائص كائن الخطأ بشكل مختلف. على سبيل المثال ، يسمى عنوان ملف البرنامج النصي البرنامج النصي في Chrome ولكن اسم الملف في Firefox. لذلك ، نحتاج أيضًا إلى وظيفة خاصة لتطبيع كائن الخطأ ، أي لرسم خريطة أسماء السمات المختلفة إلى اسم سمة موحدة. لممارسات محددة ، يرجى الرجوع إلى هذه المقالة. على الرغم من أنه سيتم تحديث تطبيق المتصفح ، إلا أنه لن يكون من الصعب للغاية على أي شخص الحفاظ على جدول التعيين هذا.
مماثل هو تنسيق تتبع المكدس. تقوم هذه الخاصية بحفظ معلومات المكدس من استثناء عند حدوثها في نص عادي. نظرًا لأن تنسيقات النص المستخدمة من قبل كل متصفح مختلفة ، فمن الضروري أيضًا الحفاظ على تعبير منتظم لاستخراج اسم الوظيفة (المعرف) والملف (البرنامج النصي) ورقم السطر (السطر) ورقم العمود (العمود) لكل إطار من نص عادي.
قيود الأمن
إذا كنت قد واجهت أيضًا خطأً في رسالة "خطأ البرنامج النصي". سوف تفهم ما أتحدث عنه ، وهو في الواقع قيود المتصفح لملفات البرنامج النصي من مصادر مختلفة. سبب قيود الأمن هذا هو كما يلي: لنفترض أن HTML الذي تم إرجاعه بواسطة مصرفي عبر الإنترنت بعد تسجيل الدخول يختلف عن HTML الذي يراه مستخدم مجهول ، يمكن لموقع الويب الخاص بجهات خارجية أن يضع URI لهذا البنك عبر الإنترنت في سمة Script.SRC. بالطبع ، لا يمكن تحليل HTML كـ JS ، وبالتالي فإن المتصفح سوف يلقي استثناءً ، ويمكن لهذا الموقع التابع لجهة خارجية تحديد ما إذا كان المستخدم قد تم تسجيل الدخول من خلال تحليل موقع الاستثناء. لهذا السبب ، يقوم المتصفح بتصفية جميع الاستثناءات التي تم إلقاؤها بواسطة ملفات البرنامج النصي المصدر المختلفة ، وترك رسالة غير متغيرة فقط مثل "خطأ البرنامج النصي." ، وتختفي جميع السمات الأخرى.
بالنسبة لمواقع الويب ذات النطاق المحدد ، من الطبيعي أن يتم وضع ملفات البرنامج النصي على CDN ويتم وضع مصادر مختلفة. الآن حتى لو قمت بإنشاء موقع ويب صغير بنفسك ، يمكن للأطر الشائعة مثل jQuery و Backbone الرجوع مباشرة إلى الإصدار على CDN العام لتسريع تنزيلات المستخدم. لذا فإن هذا التقييد الأمني يتسبب في بعض المتاعب ، مما يتسبب في معلومات الاستثناء التي نجمعها من Chrome و Firefox ليكون "خطأ سيناريو" عديمة الفائدة.
كورس
إذا كنت ترغب في تجاوز هذا التقييد ، فما عليك سوى تأكد من أن ملف البرنامج النصي والصفحة نفسها من نفس الأصل. ولكن ألا يضع ملفات البرنامج النصي على الخوادم التي لا تسارعها CDN لإبطاء سرعة تنزيل المستخدم؟ يتمثل أحد الحلول في متابعة وضع ملف البرنامج النصي على CDN ، واستخدام XMLHTTPrequest لتنزيل المحتوى مرة أخرى من خلال CORS ، ثم إنشاء علامة <script> لضخه في الصفحة. الرمز المضمن في الصفحة هو بالطبع نفس الأصل.
هذا أمر بسيط القول ، ولكن هناك العديد من التفاصيل التي يجب تنفيذها. لإعطاء مثال بسيط:
نسخة الكود كما يلي:
<script src = "http://cdn.com/step1.js"> </script>
<script>
(وظيفة Step2 () {}) () ؛
</script>
<script src = "http://cdn.com/step3.js"> </script>
نعلم جميعًا أنه إذا كانت هناك تبعيات في Step1 و Step2 و Step3 ، فيجب تنفيذها بشكل صارم في هذا الترتيب ، وإلا فقد يحدث خطأ. يمكن للمتصفح طلب ملفات Step1 و Step3 بالتوازي ، ولكن يتم ضمان الطلب عند تنفيذها. إذا حصلنا على محتويات الملف لـ Step1 و Step3 باستخدام XMLHTTPrequest ، فنحن بحاجة إلى التأكد من الترتيب الصحيح من قبل أنفسنا. بالإضافة إلى ذلك ، لا تنسى الخطوة 2. يمكن تنفيذ Step2 عند تنزيل Step1 في نموذج غير محظور ، لذلك يجب أن نتدخل أيضًا مع Step2 ودعه ينتظر إكمال Step1 قبل التنفيذ.
إذا كان لدينا بالفعل مجموعة كاملة من الأدوات لإنشاء علامات <script> لصفحات مختلفة على موقع الويب ، فنحن بحاجة إلى ضبط هذه المجموعة من الأدوات لإجراء تغييرات على <script> العلامات:
نسخة الكود كما يلي:
<script>
SchedulerEmotescript ('http://cdn.com/step1.js') ؛
</script>
<script>
matherinlinescript (وظيفة الدالة () {
(وظيفة Step2 () {}) () ؛
}) ؛
</script>
<script>
SchedulerEmotescript ('http://cdn.com/step3.js') ؛
</script>
نحتاج إلى تنفيذ وظيفتين SchedulerEmotesScript و MazerInlinescript ، والتأكد من تعريفهما قبل علامة <script> الأولى التي تشير إلى ملف البرنامج النصي الخارجي ، ثم سيتم إعادة كتابة علامات <script> المتبقية في النموذج أعلاه. لاحظ أنه تم وضع وظيفة Step2 التي تم تنفيذها على الفور في وظيفة رمز أكبر. لن يتم تنفيذ وظيفة الكود ، إنها مجرد حاوية ، بحيث يمكن الاحتفاظ برمز Step2 الأصلي دون الهروب ، ولكن لن يتم تنفيذه على الفور.
بعد ذلك ، نحتاج إلى تنفيذ آلية كاملة للتأكد من أن محتوى الملف الذي تم تنزيله بواسطة SchedulerEmotescript استنادًا إلى العنوان ويمكن تنفيذ الكود الذي تم الحصول عليه مباشرة بواسطة MAZEDINLINESCRIPT واحداً تلو الآخر بالترتيب الصحيح. لن أعطي الكود التفصيلي هنا. إذا كنت مهتمًا ، فيمكنك تنفيذها بنفسك.
فحص رقم الخط
يمكن أن يؤدي الحصول على المحتوى من خلال الكورس والحقن في الصفحة إلى اختراق قيود الأمان ، ولكنه سيؤدي إلى مشكلة جديدة ، أي تعارضات عدد الخط. في الأصل ، يمكن تحديد موقع ملف البرنامج النصي الفريد من خلال error.script ، ثم يمكن تحديد رقم السطر الفريد من خلال error.line. الآن ، نظرًا لأن جميع الرموز المضمنة في الصفحة كلها رموز ، لا يمكن تمييز علامات <script> المتعددة بواسطة Error.script. ومع ذلك ، يتم حساب رقم السطر داخل كل علامة <script> من 1 ، مما يؤدي إلى عدم القدرة على استخدام معلومات الاستثناء لتحديد موقع رمز المصدر حيث يوجد الخطأ.
لتجنب تعارض عدد الخط ، يمكننا أن نضيع بعض أرقام الأسطر بحيث لا تتداخل فترات رقم السطر المستخدمة بواسطة الكود الفعلي في كل علامة <script> مع بعضها البعض. على سبيل المثال ، على افتراض أن الكود الفعلي في كل علامة <script> لا يتجاوز 1000 سطر ، ثم يمكنني السماح للرمز في السطر الأول <script> احتلال علامة 11000 ، والرمز في السطر الثاني <script> TACK LUSCE 10012000 (تم إدراج 1000 سطر فارغ من قبل) ، والرمز في السطر الثالث <script> يتخذ السطر 20013000 (2000 خطوط فارغة من قبل). ثم نستخدم سمة البيانات-* لتسجيل هذه المعلومات لسهولة التحقق من الظهر.
نسخة الكود كما يلي:
<السيناريو
data-src = "http://cdn.com/step1.js"
سطر البيانات start = "1"
>
// كود للخطوة 1
</script>
<script data-line-start = "1001">
// '/n' * 1000
// رمز الخطوة 2
</script>
<السيناريو
Data-Src = "http://cdn.com/step3.js"
خط البيانات start = "2001"
>
// '/n' * 2000
// كود للخطوة 3
</script>
بعد هذه المعالجة ، إذا كان خطأ الخطأ. السطر هو 3005 ، فهذا يعني أن الخطأ الفعلي.
بالطبع ، نظرًا لأننا لا نستطيع أن نضمن أن كل ملف نص برمجي يحتوي على 1000 سطر فقط ، فمن الممكن أيضًا أن تكون بعض ملفات البرنامج النصي أقل بكثير من 1000 سطر ، لذلك ليست هناك حاجة لتخصيص فاصل سطر 1000 لكل علامة <script>. يمكننا تخصيص فترات زمنية استنادًا إلى العدد الفعلي لخطوط النصوص ، فقط التأكد من عدم تداخل الفواصل الزمنية المستخدمة بواسطة كل علامة <script>.
سمة crossorigin
لا تقتصر القيود الأمنية التي تفرضها المتصفحات على المحتوى من مصادر مختلفة بالطبع على علامات <script>. نظرًا لأن xmlhttprequest يمكن أن يخترق هذا القيد من خلال الكورس ، فلماذا يتم الرجوع إلى الموارد مباشرة من خلال العلامات غير المسموح بها؟ هذا بالتأكيد جيد.
ينطبق أيضًا على الحد من الإشارة إلى ملفات البرنامج النصي المصدر المختلفة لـ <script> أيضًا إلى الإشارة إلى ملفات صور مصدر مختلفة لـ <img>. إذا كانت علامة <IMG> مصدرًا مختلفًا ، بمجرد استخدامها في الرسم <Canvas> ، ستصبح <Canvas> حالة كتابة فقط ، مما يضمن أن موقع الويب لا يمكنه سرقة بيانات الصورة غير المصرح بها من مصادر مختلفة عبر JavaScript. في وقت لاحق ، حلت علامة <img> هذه المشكلة عن طريق تقديم سمة crossorigin. إذا كان crossorigin = "مجهول" ، فهو يعادل الكورس المجهول ؛ إذا كانت crossorigin = "استخدام الاستخدام" ، فهي تعادل كورس معتمدة.
نظرًا لأن علامة <img> يمكن أن تفعل ذلك ، فلماذا لا تستطيع علامة <script> القيام بذلك؟ لذا أضافت الشركة المصنعة للمتصفح نفس سمة Crossorigin إلى علامة <script> لحل القيود الأمنية أعلاه. الآن دعم Chrome و Firefox لهذا العقار مجاني تمامًا. سوف تتعامل Safari مع crossorigin = "مجهول" كـ crossorigin = "use-credentials" ، والنتيجة هي أنه إذا كان الخادم يدعم فقط cors مجهول ، فإن Safari سوف يعامل المصادقة على أنه فشل. نظرًا لأن خادم CDN مصمم لإرجاع المحتوى الثابت فقط لأسباب الأداء ، فمن المستحيل إعادة ديناميكي رأس HTTP المطلوب لمصادقة CORS بناءً على الطلبات. Safari يعادل عدم القدرة على استخدام هذه الميزة لحل المشكلة أعلاه.
لخص
يبدو معالجة استثناء JavaScript بسيطة ولا تختلف عن اللغات الأخرى ، ولكن ليس من السهل التقاط جميع الاستثناءات وتحليل الخصائص. الآن ، على الرغم من أن بعض خدمات الطرف الثالث توفر خدمات شبيهة بـ Google Analytics التي تلتقط استثناءات JavaScript ، إذا كنت ترغب في فهم التفاصيل والمبادئ ، فلا يزال يتعين عليك القيام بذلك بنفسك.