على أي حال ، طالما فشل التحديث في التكاثر بعد خطأ JavaScript ، يمكن للمستخدم حل المشكلة عن طريق التحديث ، ولن يعطل المتصفح ، وسيكون على ما يرام إذا لم يحدث. كان هذا الافتراض صحيحًا قبل أن يصبح تطبيق الصفحة الواحدة شائعة. تطبيق الصفحة الفردية الحالية معقد للغاية بعد تشغيله لفترة من الوقت. ألن تقوم بإعادة صياغة العمليات السابقة تمامًا؟ لذلك لا يزال من الضروري بالنسبة لنا التقاط معلومات الاستثناء هذه وتحليلها ، ثم يمكننا تعديل الكود لتجنب التأثير على تجربة المستخدم.
كيفية التقاط الاستثناءات لقد كتبنا أنفسنا throw new Error() وهو ما يمكننا بالتأكيد التقاطه إذا أردنا التقاط ، لأننا نعرف جيدًا أين تتم كتابة throw . ومع ذلك ، فإن الاستثناءات التي تحدث عند استدعاء واجهة برمجة تطبيقات المتصفح ليست سهلة للقبض. بالنسبة إلى الأول ، يمكننا أيضًا التقاطها من خلال try-catch ، وللأخير ، يجب أن نستمع إلى استثناءات عالمية ثم التمسك بها.
إذا كان من المعروف أن بعض واجهات برمجة تطبيقات المتصفح ترمي الاستثناءات ، فنحن بحاجة إلى وضع المكالمة في try-catch لتجنب البرنامج بأكمله الذي يدخل دولة غير قانونية بسبب الأخطاء. على سبيل المثال ، سيتم طرح window.localStorage مثل API.
try {localstorage.setitem ('date' ، date.now ()) ؛
} catch (خطأ) {
المراسل (خطأ) ؛
}
سيناريو آخر مشترك try-catch هو عمليات الاسترجاعات. نظرًا لأن رمز وظيفة رد الاتصال أمر لا يمكن السيطرة عليه ، فإننا لا نعرف مدى جودة الكود ، وما إذا كان سيتم استدعاء واجهات برمجة التطبيقات الأخرى التي ترمي استثناءات. لكي لا تتسبب في تنفيذ رموز أخرى بعد استدعاء رد الاتصال بسبب أخطاء رد الاتصال ، من الضروري إعادة الاتصال إلى try-catch .
listeners.forEach(function(listener) {يحاول {
المستمع () ؛
} catch (خطأ) {
المراسل (خطأ) ؛
}
}) ؛
بالنسبة للأماكن التي لا يمكن try-catch ، في حالة حدوث استثناء ، لا يمكن اكتشافها إلا من خلال window.onerror .
window.onerror =دالة (errormessage ، scripturi ، الكتان) {
المراسل ({
الرسالة: errormessage ،
السيناريو: Scripturi ،
الخط: عدد الكتان
}) ؛
}
احرص على عدم أن تكون ذكيًا واستخدم window.addEventListener أو window.attachEvent للاستماع إلى window.onerror . العديد من المتصفحات تنفذ فقط window.onerror ، أو فقط تنفيذ window.onerror هو قياسي. بالنظر إلى أن المسودة القياسية تحدد أيضًا window.onerror ، نحتاج فقط إلى استخدام window.onerror .
لنفترض أن لدينا وظيفة reportError لجمع استثناءات تم صيدها ثم إرسالها على دفعات إلى تخزين من جانب الخادم للاستعلام والتحليل ، ثم ما هي المعلومات التي نريد جمعها؟ تتضمن المزيد من المعلومات المفيدة: نوع الخطأ ( name ) ، رسالة خطأ ( message ) ، عنوان ملف البرنامج النصي ( script ) ، رقم السطر ( line ) ، رقم العمود ( column ) ، وتتبع المكدس ( stack ). إذا تم اكتشاف استثناء من خلال try-catch ، فإن كل هذه المعلومات موجودة على كائن Error (بدعم من المتصفحات السائدة) ، بحيث يمكن reportError أيضًا جمع هذه المعلومات. ولكن إذا تم التقاطها من خلال window.onerror ، نعلم جميعًا أن وظيفة الحدث هذه لديها 3 معلمات فقط ، وبالتالي فقدت المعلومات غير المتوقعة لهذه المعلمات الثلاثة.
إذا تم إنشاء كائن Error من قبل أنفسنا ، فسيتم التحكم في error.message من قبلنا. في الأساس ، ما وضعناه في error.message ، ما الذي سيكون المعلمة الأولى ( message ) من window.onerror . (سيقوم المتصفح فعليًا بالتعديل قليلاً ، مثل إضافة 'Uncaught Error: ' بادئة.) لذلك ، يمكننا تسلسل السمات التي نشعر بالقلق (مثل JSON.Stringify ) وتخزينها في error.message لهم في window.onerror بالطبع ، يقتصر هذا على كائنات Error التي ننشئها أنفسنا.
يعرف مصنعو المتصفح أيضًا القيود التي يخضع لها الأشخاص عند استخدام window.onerror ، بحيث يبدأون في إضافة معلمات جديدة إلى window.onerror . بالنظر إلى أن أرقام الصفوف فقط وعدم وجود أرقام أعمدة تبدو متناظرة للغاية ، أي إضافة أرقام الأعمدة أولاً ووضعها في المعلمة الرابعة. ومع ذلك ، فإن ما يقلقه الجميع أكثر هو ما إذا كان بإمكانهم الحصول على المكدس الكامل ، لذلك قال Firefox إنه سيكون من الأفضل وضع المكدس في المعلمة الخامسة. لكن Chrome قال إنه من الأفضل وضع كائن Error بأكمله في المعلمة الخامسة ، ويمكنك قراءة أي سمات ، بما في ذلك السمات المخصصة. نتيجة لذلك ، يتحرك Chrome بشكل أسرع ، يتم تنفيذ window.onerror جديدة. يتم تنفيذ توقيع الإرهاق في Chrome 30 ، مما يؤدي إلى الكتابة التالية للمشروع القياسي.
انتظام السماتwindow.onerror = function(errormessage ،
scripturi ،
عدد الكتان ،
عدد الأعمدة ،
خطأ
) {
إذا (خطأ) {
المراسل (خطأ) ؛
} آخر {
المراسل ({
الرسالة: errormessage ،
السيناريو: Scripturi ،
الخط: عدد الكتان ،
العمود: عدد العمود
}) ؛
}
}
أسماء سمات كائن Error التي ناقشناها script قبل تعتمد filename أساليب Error الكروم. لذلك ، نحتاج أيضًا إلى وظيفة خاصة لتطبيع كائن Error ، أي لرسم خريطة أسماء السمات المختلفة إلى اسم سمة موحدة. لممارسات محددة ، يرجى الرجوع إلى هذه المقالة. على الرغم من أنه سيتم تحديث تطبيق المتصفح ، إلا أنه لن يكون من الصعب للغاية على أي شخص الحفاظ على جدول التعيين هذا.
مماثل هو تنسيق تتبع stack . تقوم هذه الخاصية بحفظ معلومات المكدس عند حدوثها في شكل نص عادي. identifier script line column
إذا واجهت أيضًا خطأً في رسالة 'Script error.' سبب قيود الأمن هذا هو كما يلي: لنفترض أن HTML الذي تم إرجاعه بواسطة مصرفي عبر الإنترنت بعد تسجيل الدخول يختلف عن HTML الذي يراه مستخدم مجهول ، يمكن لموقع الويب التابع لجهة خارجية وضع URI لهذا البنك عبر الإنترنت في script.src سمة script.src . بالطبع ، لا يمكن تحليل HTML كـ JS ، وبالتالي فإن المتصفح سوف يلقي استثناءً ، ويمكن لهذا الموقع التابع لجهة خارجية تحديد ما إذا كان المستخدم قد تم تسجيل الدخول من خلال تحليل موقع الاستثناء. لهذا السبب ، يقوم المتصفح بتصفية جميع الاستثناءات التي يتم إلقاؤها بواسطة ملفات البرنامج النصي المختلفة ، وترك رسالة دون تغيير فقط مثل 'Script error.'
بالنسبة لمواقع الويب ذات النطاق المحدد ، من الطبيعي أن يتم وضع ملفات البرنامج النصي على CDN ويتم وضع مصادر مختلفة. الآن حتى لو قمت بإنشاء موقع ويب صغير بنفسك ، يمكن للأطر الشائعة مثل jQuery و Backbone الرجوع مباشرة إلى الإصدار على CDN العام لتسريع تنزيلات المستخدم. لذلك فإن هذا التقييد الأمني يتسبب في بعض المتاعب ، مما يتسبب في معلومات الاستثناء التي نجمعها من Chrome و Firefox 'Script error.' .
إذا كنت ترغب في تجاوز هذا التقييد ، فما عليك سوى التأكد من أن ملف البرنامج النصي والصفحة نفسها متماثلان. ولكن ألا يضع ملفات البرنامج النصي على الخوادم التي لا تتسارع بواسطة 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 ، فنحن بحاجة إلى التأكد من الترتيب الصحيح الخاص بنا. بالإضافة إلى ذلك ، لا تنسى Step2.
إذا كان لدينا بالفعل مجموعة كاملة من الأدوات لإنشاء علامات <script> لصفحات مختلفة على موقع الويب ، فنحن بحاجة إلى ضبط هذه المجموعة من الأدوات لإجراء تغييرات على <script> العلامات:
<script>SchedulerEmotescript ('http://cdn.com/step1.js') ؛
</script>
<script>
matherinlinescript (وظيفة الدالة () {
(وظيفة Step2 () {}) () ؛
}) ؛
</script>
<script>
SchedulerEmotescript ('http://cdn.com/step3.js') ؛
</script>
نحتاج إلى تنفيذ وظيفتي scheduleRemoteScript و scheduleInlineScript ، والتأكد من تحديدها قبل علامة <script> الأولى التي تشير إلى ملف البرنامج النصي الخارجي ، ثم تتم إعادة كتابة علامات <script> المتبقية في النموذج أعلاه. لاحظ أنه تم وضع وظيفة step2 التي تم تنفيذها على الفور في وظيفة code أكبر. لن يتم تنفيذ وظيفة code ، فهي مجرد حاوية ، بحيث يمكن الاحتفاظ برمز Step2 الأصلي دون الهروب ، ولكن لن يتم تنفيذه على الفور.
بعد ذلك ، نحتاج إلى تنفيذ آلية كاملة للتأكد من أن محتوى الملف الذي تم تنزيله بواسطة scheduleRemoteScript استنادًا إلى العنوان ويمكن تنفيذ الكود الذي تم الحصول عليه مباشرة بواسطة scheduleInlineScript واحداً تلو الآخر بالترتيب الصحيح. لن أعطي الكود التفصيلي هنا.
يمكن أن يؤدي الحصول على المحتوى من خلال الكورس والحقن في الصفحة إلى اختراق قيود الأمان ، ولكنه سيؤدي إلى مشكلة جديدة ، أي تعارضات عدد الخط. في الأصل ، يمكن تحديد موقع ملف البرنامج النصي الفريد من خلال error.script ، ثم يمكن تحديد رقم السطر الفريد من خلال error.line . الآن ، نظرًا لأن جميع الرموز المضمنة في الصفحة <script> لا يمكن تمييز علامات <script> المتعددة عن طريق error.script . موقع رمز المصدر حيث توجد معلومات استثناء.
لتجنب تعارض عدد الخط ، يمكننا أن نضيع بعض أرقام الأسطر بحيث لا تتداخل فترات رقم السطر المستخدمة بواسطة الكود الفعلي في كل علامة <script> مع بعضها البعض. على سبيل المثال ، على افتراض أن الكود الفعلي في كل علامة <script> لا يتجاوز 1000 سطر ، ثم يمكنني السماح للرمز في العلامة الأولى <script> بتناول السطر 11000 والسماح للعلامة الثانية <script> في الكود في الرمز يحتل السطر 10012000 (1000 سطر فارغ تم إدخاله قبل الإدراج) ، يحتل رمز العلامة الثالثة <script> السطر 20013000 (2000 خط فارغ تم إدخاله قبل الإدراج) ، وهكذا. ثم نستخدم سمة data-* لتسجيل هذه المعلومات لسهولة التحقق من الظهر.
<scriptdata-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>
بعد هذه المعالجة ، إذا كان خطأ خطأ error.line هو 3005 5 error.line يعني أن error.script الفعلي 'http://cdn.com/step3.js' يمكننا إكمال رقم السطر هذا العكسي في وظيفة reportError المذكورة سابقًا.
بالطبع ، نظرًا لأننا لا نستطيع أن نضمن أن كل ملف نصي يحتوي على 1000 سطر فقط ، فمن الممكن أيضًا أن تكون بعض ملفات البرنامج النصي أقل بكثير من 1000 سطر ، لذلك ليست هناك حاجة لتخصيص 1000 سطر لكل علامة <script> . يمكننا تخصيص فترات زمنية استنادًا إلى العدد الفعلي لخطوط النصوص ، فقط التأكد من عدم تداخل الفواصل الزمنية المستخدمة بواسطة كل علامة <script> .
لا تقتصر القيود الأمنية التي تفرضها المتصفحات على المحتوى من مصادر مختلفة بالطبع على علامة <script> . نظرًا لأن XMLHttpRequest يمكن أن يخترق هذا القيد من خلال الكورس ، فلماذا يتم الرجوع إلى الموارد مباشرة من خلال العلامات غير المسموح بها؟ هذا بالتأكيد جيد.
ينطبق أيضًا على الحد من الإشارة إلى ملفات البرنامج النصي المصدر المختلفة لـ <script> أيضًا إلى الإشارة إلى ملفات صور مصدر مختلفة لـ <img> . إذا كانت علامة <img> مصدرًا مختلفًا ، بمجرد استخدامها في الرسم <canvas> ، ستصبح <canvas> حالة كتابة فقط ، مما يضمن أن موقع الويب لا يمكنه سرقة بيانات الصورة غير المصرح بها من مصادر مختلفة عبر JavaScript. في وقت لاحق ، حلت علامة <img> هذه المشكلة عن طريق تقديم سمة crossorigin . إذا تم استخدام crossorigin="anonymous" ، فهذا يعادل كورس مجهول.
نظرًا لأن علامة <img> يمكن أن تفعل ذلك ، فلماذا لا تستطيع علامة <script> القيام بذلك؟ لذلك ، أضافت الشركة المصنعة للمستعرض نفس سمة crossorigin إلى علامة <script> لحل القيود الأمنية أعلاه. الآن دعم Chrome و Firefox لهذا العقار مجاني تمامًا. سوف تتعامل Safari مع crossorigin="anonymous" كـ crossorigin="use-credentials" ، والنتيجة هي أنه إذا كان الخادم يدعم فقط cors مجهول ، فإن Safari سوف يعامل المصادقة على أنه فشل. نظرًا لأن خادم CDN مصمم لإرجاع المحتوى الثابت فقط لأسباب الأداء ، فمن المستحيل إرجاع رأس HTTP المطلوب بشكل حيوي لمصادقة CORS بناءً على الطلبات.
يبدو معالجة استثناء JavaScript بسيطة ولا تختلف عن اللغات الأخرى ، ولكن ليس من السهل التقاط جميع الاستثناءات وتحليل الخصائص. على الرغم من أن بعض خدمات الطرف الثالث توفر الآن خدمات Google Analytics التي تلتقط استثناءات JavaScript ، إذا كنت ترغب في فهم التفاصيل والمبادئ ، فيجب عليك القيام بذلك بنفسك.