تصحيح أخطاء JavaScript غير المتزامنة باستخدام "أدوات مطوري البرامج في Chrome"

مقدمة

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

لحسن الحظ، يمكنك الآن في "أدوات مطوري البرامج في Chrome" عرض السلسلة الكاملة لطلبات الاتصال بوظائف الاستدعاء غير المتزامنة لـ JavaScript.

نظرة عامة سريعة على حِزم الاستدعاءات غير المتزامنة
نظرة عامة سريعة على مجموعات استدعاءات غير متزامنة (سنوضّح خطوات هذا العرض التوضيحي قريبًا).

بعد تفعيل ميزة تسلسل المكالمات غير المتزامنة في "أدوات المطوّر"، ستتمكّن من التوغّل في حالة تطبيق الويب في نقاط زمنية مختلفة. اطّلِع على مسار التتبّع الكامل للبعض من مستمعي الأحداث وsetInterval وsetTimeout وXMLHttpRequest والوعود وrequestAnimationFrame وMutationObservers وغير ذلك.

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

لنفعّل هذه الميزة ونلقي نظرة على بعض هذه السيناريوهات.

تفعيل تصحيح الأخطاء غير المتزامنة في Chrome

يمكنك تجربة هذه الميزة الجديدة من خلال تفعيلها في Chrome. انتقِل إلى لوحة المصادر في "أدوات مطوّري البرامج في Chrome Canary".

بجانب لوحة تسلسل استدعاء الدوال البرمجية على يسار الصفحة، يتوفّر مربّع اختيار جديد لـ "غير متزامن". بدِّل مربّع الاختيار لتفعيل ميزة تصحيح الأخطاء غير المتزامنة أو إيقافها. (مع أنّه بعد تفعيلها، قد لا تريد إيقافها مطلقًا).

فعِّل ميزة "التحميل غير المتزامن" أو أوقِفها.

تسجيل أحداث الموقّت المتأخرة وردود XHR

من المرجّح أنّك رأيت هذا الرمز من قبل في Gmail:

يحاول Gmail إعادة إرسال رسالة إلكترونية.

إذا حدثت مشكلة في إرسال الطلب (إما أنّ الخادم يواجه مشاكل أو أنّ هناك مشاكل في الاتصال بالشبكة من جهة العميل)، سيحاول Gmail تلقائيًا إعادة إرسال الرسالة بعد مهلة قصيرة.

لمعرفة كيف يمكن أن تساعدنا تسلسلات المكالمات غير المتزامنة في تحليل أحداث الموقّت المتأخر واستجابات XHR، أعدتُ هذه العملية باستخدام مثال محاكاة على Gmail. يمكن العثور على رمز JavaScript الكامل في الرابط أعلاه، ولكن العملية هي على النحو التالي:

مخطّط بياني لتدفق مثال Gmail وهمي
في المخطّط البياني أعلاه، تُعدّ الطرق التي تم تمييزها باللون الأزرق هي المواضع الرئيسية التي تُظهر ميزة DevTool الجديدة هذه على أنّها الأكثر فائدة، لأنّ هذه الطرق تعمل بشكل غير متزامن.

من خلال النظر فقط إلى لوحة "تسلسل استدعاء الدوال البرمجية" في الإصدارات السابقة من "أدوات مطوّري البرامج"، لن يمنحك نقطة التوقف فيpostOnFail() سوى معلومات قليلة عن مكان استدعاءpostOnFail(). ولكن اطّلِع على الفرق عند تفعيل الأداة المتعدّدة المهام غير المتزامنة:

قبل
نقطة توقُّف تم ضبطها في مثال Gmail وهمي بدون تجميعات طلبات غير متزامنة
لوحة "تسلسل استدعاء الدوال البرمجية" بدون تفعيل وضع "الاستدعاء غير المتزامن"

يمكنك هنا الاطّلاع على أنّه تمّ بدء postOnFail() من خلال طلب معاودة اتصال AJAX، ولكن لا تتوفّر أي معلومات أخرى.

بعد
نقطة توقُّف تم ضبطها في مثال Gmail وهمي مع توفُّر تسلسلات استدعاءات غير متزامنة
لوحة "حزمة التنفيذ" مع تفعيل وضع "غير متزامن"

يمكنك هنا الاطّلاع على أنّ طلب XHR قد بدأ من submitHandler(). أحسنت.

عند تفعيل تسلسلات المكالمات غير المتزامنة، يمكنك عرض تسلسل المكالمات بالكامل لتحديد ما إذا كان الطلب قد بدأ من submitHandler() (يحدث ذلك بعد النقر على زر الإرسال) أو من retrySubmit() (يحدث ذلك بعد تأخير setTimeout()):

submitHandler()
نقطة توقُّف تم ضبطها في مثال Gmail وهمي مع توفُّر تسلسلات استدعاءات غير متزامنة
retrySubmit()
نقطة توقّف أخرى تم ضبطها في مثال Gmail وهمي مع توفّر تسلسلات استدعاءات غير متزامنة

مشاهدة تعبيرات المشاهدة بشكل غير متزامن

عند مراجعة تسلسل استدعاء الدوالّ بالكامل، سيتم أيضًا تعديل التعبيرات التي تمّت مراقبتها لعكس الحالة التي كانت عليها في ذلك الوقت.

مثال على استخدام تعبيرات المراقبة مع توفّر مجموعات طلبات للاتصال بشكل غير متزامن

تقييم الرمز البرمجي من النطاقات السابقة

بالإضافة إلى مراقبة التعبيرات، يمكنك التفاعل مع الرمز من النطاقات السابقة مباشرةً في لوحة وحدة تحكّم JavaScript في أدوات مطوّري البرامج.

لنفترض أنّك الدكتور "هو" وتحتاج إلى مساعدة صغيرة في مقارنة الساعة من قبل دخولك إلى "تارديس" إلى "الآن". من وحدة تحكّم DevTools، يمكنك بسهولة تقييم القيم وتخزينها وإجراء العمليات الحسابية عليها من نقاط تنفيذ مختلفة.

مثال على استخدام وحدة تحكّم JavaScript مع تسلسلات استدعاءات غير متزامنة
استخدِم وحدة تحكّم JavaScript مع تسلسلات استدعاءات غير متزامنة لتصحيح أخطاء الرمز البرمجي. يمكنك الاطّلاع على العرض الترويجي أعلاه هنا.

سيوفّر لك البقاء في "أدوات مطوّري البرامج" لتعديل التعبيرات وقتًا من خلال عدم الحاجة إلى التبديل مرة أخرى إلى رمز المصدر وإجراء التعديلات وتحديث المتصفّح.

حلّ قرارات الوعود المتسلسلة

إذا كنت تعتقد أنّه كان من الصعب حلّ عملية Gmail النموذجية السابقة بدون تفعيل ميزة التسلسل المتزامن لطلبات الاتصال، هل يمكنك تخيل مدى صعوبة حلّها باستخدام عمليات معقدة أكثر من عمليات التسلسل غير المتزامن، مثل الوعود المتسلسلة؟ لنطّلِع مجددًا على المثال الأخير من البرنامج التعليمي الذي أعدّه "جاك أرشيبالد" حول وعود JavaScript.

في ما يلي صورة متحركة صغيرة لعرض تسلسلات استدعاء الدوالّ في مثال async-best-example.html الذي أعدّه "جاك".

قبل
نقطة توقّف تم ضبطها في مثال الوعد بدون توفّر تسلسلات مكالمات غير متزامنة
لوحة "تسلسل استدعاء الدوال البرمجية" بدون تفعيل وضع "الاستدعاء غير المتزامن"

لاحظ أنّ لوحة "تسلسل استدعاء الدوال البرمجية" لا تتضمّن الكثير من المعلومات عند محاولة تصحيح أخطاء الوعود.

بعد
نقطة توقف تم ضبطها في مثال الوعد مع توفّر تسلسلات مكالمات غير متزامنة
لوحة "حزمة التنفيذ" مع تفعيل وضع "غير متزامن"

ممتاز. هذه الوعود عمليات معاودة اتصال كثيرة.

الحصول على إحصاءات عن الصور المتحركة على الويب

لنطّلع على المزيد من المعلومات في أرشيف HTML5Rocks. هل تذكر مقالة "بول لويس" بعنوان إنشاء صور متحركة أكثر كفاءةً وسرعةً باستخدام requestAnimationFrame؟

افتح العرض التوضيحي لطلب الرسوم المتحركة وأضِف نقطة توقُّف في بداية الطريقة update()‎ (بالقرب من السطر 874) منملف post.html. باستخدام تسلسلات استدعاءات غير متزامنة، نحصل على المزيد من الإحصاءات حول requestAnimationFrame، بما في ذلك إمكانية التنقّل بالكامل إلى الخلف إلى دالة الاستدعاء لحدث الانتقال إلى أعلى أو أسفل الصفحة.

قبل
نقطة توقُّف تم ضبطها في مثال requestAnimationFrame بدون تسلسلات استدعاء الدوال البرمجية غير المتزامنة
لوحة "تسلسل استدعاء الدوال البرمجية" بدون تفعيل وضع "الاستدعاء غير المتزامن"
بعد
نقطة توقّف تم ضبطها في مثال requestAnimationFrame مع حزم استدعاءات غير متزامنة
ومع تفعيل المهام غير المتزامنة

تتبُّع تعديلات DOM عند استخدام MutationObserver

MutationObserver تسمح لنا برصد التغييرات في DOM. في هذا المثال البسيط، عند النقر على الزر، تتم إضافة عقدة DOM جديدة إلى <div class="rows"></div>.

أضِف نقطة توقف في nodeAdded() (السطر 31) في demo.html. عند تفعيل توفُّر ملف برمجي دوار لسلسلة معالجة طلبات addNode()، يمكنك الآن التنقّل في تسلسل استدعاء الدوالّ من خلال addNode() إلى حدث النقر الأولي.

قبل
نقطة توقّف تم ضبطها في مثال mutationObserver بدون تجميعات المكالمات غير المتزامنة
لوحة "تسلسل استدعاء الدوال البرمجية" بدون تفعيل وضع "الاستدعاء غير المتزامن"
بعد
نقطة توقّف تم ضبطها في مثال mutationObserver مع توفّر تسلسلات استدعاء غير متزامنة
ومع تفعيل المهام غير المتزامنة

نصائح لتصحيح أخطاء JavaScript في تسلسلات استدعاء الدوال البرمجية غير المتزامنة

تسمية الدوالّ

إذا كنت تميل إلى تعيين جميع وظائف الاستدعاء كوظائف مجهولة الهوية، قد تحتاج بدلاً من ذلك إلى منحها اسمًا لتسهيل عرض تسلسل استدعاء الدوال البرمجية.

على سبيل المثال، لنأخذ دالة مجهولة الهوية على النحو التالي:

window.addEventListener('load', function() {
  // do something
});

وامنحه اسمًا مثل windowLoaded():

window.addEventListener('load', function <strong>windowLoaded</strong>(){
  // do something
});

عند بدء حدث load، سيظهر في "تتبُّع تسلسل استدعاء الدوال البرمجية" في DevTools مع اسم دالته بدلاً من العبارة المشفّرة "(دالة مجهولة)". يسهّل ذلك معرفة ما يحدث في تتبع تسلسل استدعاء الدوالّ في لمح البصر.

قبل
دالة مجهولة
بعد
دالة مُسمّاة

استكشاف المزيد

للتلخيص، في ما يلي جميع عمليات الاستدعاء غير المتزامنة التي ستعرض فيها أدوات المطوّر حزمة استدعاء كاملة:

  • الموقّتات: ارجع إلى حيث تمّت بدء setTimeout() أو setInterval().
  • طلبات البيانات عبر HTTP (XHR): ارجع إلى المكان الذي تم فيه استدعاء xhr.send().
  • إطارات الصور المتحركة: ارجع إلى المكان الذي تم فيه استدعاء requestAnimationFrame.
  • الوعد: يمكنك الرجوع إلى المكان الذي تم فيه حلّ وعد.
  • Object.observe: الرجوع إلى المكان الذي تم فيه ربط دالة الاستدعاء للمراقِب في الأصل
  • MutationObservers: يمكنك الرجوع إلى المكان الذي تم فيه تنشيط حدث MutationObserver.
  • window.postMessage(): تخطّي طلبات المراسلة داخل العملية
  • DataTransferItem.getAsString()
  • FileSystem API
  • IndexedDB
  • WebSQL
  • أحداث DOM المؤهَّلة من خلال addEventListener(): ارجع إلى المكان الذي تم فيه بدء الحدث. لأسباب تتعلّق بالأداء، ليست كل أحداث DOM مؤهّلة لاستخدام ميزة "تجميعات المكالمات غير المتزامنة". تشمل أمثلة الأحداث المتاحة حاليًا ما يلي: "scroll" و"hashchange" و "selectionchange".
  • أحداث الوسائط المتعددة من خلال addEventListener(): ارجع إلى المكان الذي تم فيه بدء الحدث. تشمل أحداث الوسائط المتعددة المتاحة: أحداث الصوت والفيديو (مثل "تشغيل" و"إيقاف مؤقت" و"تغيير السرعة") وأحداث WebRTC MediaStreamTrackList (مثل "إضافة مقطع صوتي" و"إزالة مقطع صوتي") وأحداث MediaSource (مثل "فتح المصدر").

من المفترض أن يساعدك الاطّلاع على تتبع تسلسل استدعاء الدوال البرمجية JavaScript الكامل في حلّ المشكلة. ستكون هذه الميزة في "أدوات المطوّر" مفيدة بشكل خاص عند حدوث أحداث متعدّدة غير متزامنة في ما يتعلّق ببعضها، أو في حال تم طرح استثناء غير محصَّل من داخل دالة استدعاء غير متزامنة.

جرِّب ذلك في Chrome. إذا كانت لديك ملاحظات حول هذه الميزة الجديدة، يُرجى التواصل معنا على أداة تتبُّع الأخطاء في "أدوات مطوّري البرامج في Chrome" أو في مجموعة "أدوات مطوّري البرامج في Chrome".