دعنا نتحدث قليلا عن كيفية مراقبة مقدار موارد وحدة المعالجة المركزية التي يستهلكها كود JavaScript. في الوقت نفسه ، أقترح بناء حديثنا حول المكونات - لبنات البناء الأساسية للتطبيق. باستخدام هذا النهج ، يمكن أن تركز أي جهود لتحسين الإنتاجية (أو الجهود المبذولة للعثور على أسباب تباطؤ البرامج) على (نأمل) شظايا صغيرة مكتفية ذاتيا من المشروع. في الوقت نفسه ، أفترض أن تطبيق الواجهة الأمامية الخاص بك ، مثله مثل العديد من المشاريع الحديثة الأخرى ، تم إنشاؤه من خلال تجميع أجزاء صغيرة من الواجهة مناسبة للاستخدام المتكرر. إذا لم يكن الأمر كذلك ، فيمكن تطبيق منطقنا على تطبيق آخر ، ولكن سيتعين عليك إيجاد طريقتك الخاصة لتقسيم الشفرة الكبيرة الحجم إلى أجزاء ويجب عليك التفكير في كيفية تحليل هذه الأجزاء.

لماذا هذا مطلوب؟
لماذا قياس استهلاك وحدة المعالجة المركزية عن طريق جافا سكريبت؟ الحقيقة هي أنه في هذه الأيام ، يرتبط أداء التطبيق في أغلب الأحيان بقدرات المعالج. اسمحوا لي أن أقتبس بحرية كلمات ستيف سودرز وبات مينان من مقابلة أجريت معها مع
Planet Performance Podcast . قال كلاهما إن أداء التطبيق لم يعد مقصورًا على إمكانيات الشبكة أو زمن الوصول إلى الشبكة. الشبكات تزداد سرعة وأسرع. بالإضافة إلى ذلك ، تعلم المطورون ضغط الردود النصية للخادم باستخدام GZIP (أو بالأحرى باستخدام brotli) واستوعبوا كيفية تحسين الصور. كل شيء بسيط للغاية.
عنق الزجاجة أداء التطبيقات الحديثة هو المعالجات. هذا صحيح بشكل خاص في بيئة المحمول. وفي الوقت نفسه ، نمت توقعاتنا حول القدرات التفاعلية لتطبيقات الويب الحديثة. نتوقع أن تعمل واجهات مثل هذه التطبيقات بسرعة فائقة وسلاسة. وكل هذا يتطلب المزيد والمزيد من كود JavaScript. بالإضافة إلى ذلك ، نحتاج أن نتذكر أن 1 ميغابايت من الصور ليست هي نفسها 1 ميغابايت من JavaScript. يتم تنزيل الصور بشكل تدريجي ، والتطبيق في هذا الوقت يحل المشاكل الأخرى. لكن كود JavaScript غالبًا ما يكون مثل هذا المورد ، والذي بدونه يتضح أن التطبيق لا يعمل. لضمان تشغيل التطبيق الحديث ، يلزم توفير كميات كبيرة من كود JS ، والتي تحتاج إلى تحليلها وتنفيذها قبل أن تعمل بالفعل. وهذه هي المهام التي تعتمد اعتمادا كبيرا على قدرات المعالج.
مؤشر الأداء
سنستخدم مثل هذا المؤشر لسرعة أجزاء التعليمات البرمجية كعدد تعليمات المعالج المطلوبة لمعالجتها. سيتيح لنا ذلك فصل القياسات عن خصائص جهاز كمبيوتر معين وعن الحالة التي كان فيها وقت القياس. المقاييس القائمة على الوقت (مثل TTI) بها الكثير من "الضوضاء". يعتمدون على حالة اتصال الشبكة ، وكذلك على أي شيء آخر يحدث على الكمبيوتر في وقت القياس. على سبيل المثال ، يمكن أن تؤثر بعض مؤشرات البرامج النصية المنفذة أثناء تحميل الصفحة التي تم فحصها ، أو الفيروسات التي تنشغل بشيء ما في عمليات الخلفية ، على مؤشرات الأداء الزمني. يمكن قول الشيء نفسه عن امتدادات المتصفح ، والتي يمكن أن تستهلك الكثير من موارد النظام وإبطاء الصفحة. عند حساب عدد تعليمات المعالج ، من ناحية أخرى ، لا يهم الوقت. يمكن أن تكون هذه المؤشرات ، كما سترى قريبًا ، مستقرة حقًا.
فكرة
إليكم الفكرة الكامنة وراء عملنا: نحن بحاجة إلى إنشاء "مختبر" يتم فيه تشغيل الكود وفحصه عند إجراء تغييرات عليه. أعني بكلمة "معمل" جهاز كمبيوتر عادي ، ربما الذي تستخدمه باستمرار. توفر لنا أنظمة التحكم في الإصدار السنانير الموجودة تحت تصرفنا والتي يمكنك من خلالها اعتراض أحداث معينة وإجراء اختبارات معينة. بالطبع ، يمكن إجراء القياسات في "المختبر" بعد الالتزام. لكنك تعلم أن التغييرات التي تم إدخالها على التعليمات البرمجية والتي وصلت إلى مرحلة الالتزام ستتم ببطء أكبر من التغييرات التي تمت كتابتها (إن وجدت). الأمر نفسه ينطبق على إصلاح شفرة بيتا للمنتج ، وإصلاح الكود الذي دخل حيز الإنتاج.
نحتاج في كل مرة يتم فيها تغيير الرمز ، ومقارنة أدائه قبل وبعد إجراء التغييرات. في القيام بذلك ، ونحن نسعى جاهدين لاستكشاف المكونات في عزلة. نتيجة لذلك ، سنكون قادرين على رؤية المشاكل بوضوح ونكون قادرين على معرفة أين تنشأ بالضبط.
الشيء الجيد هو أنه يمكن إجراء مثل هذه الدراسات في متصفح حقيقي ، باستخدام Puppeteer ، على سبيل المثال. هذه هي الأداة التي تتيح لك التحكم في المتصفح دون واجهة مستخدم من Node.js.
رمز البحث للبحث
من أجل العثور على رمز الدراسة ، يمكننا الرجوع إلى أي دليل نمط ، أو إلى أي نظام تصميم. بشكل عام ، نحن سعداء بأي شيء يقدم أمثلة مختصرة ومعزولة عن استخدام المكونات.
ما هو "دليل الأسلوب"؟ عادة ما يكون هذا تطبيق ويب يوضح جميع المكونات أو "العناصر الأساسية" لعناصر واجهة المستخدم المتاحة للمطور. يمكن أن تكون إما مكتبة معينة من مكونات الطرف الثالث ، أو شيء تم إنشاؤه بجهودك الخاصة.
أثناء البحث عن مثل هذه المشروعات على الإنترنت ، صادفت سلسلة مناقشة حديثة حول Twitter تحدثت عن مكتبات جديدة نسبياً لمكونات React. نظرت إلى العديد من المكتبات المذكورة هناك.
ليس من المستغرب أن يتم تزويد المكتبات الحديثة عالية الجودة بوثائق تتضمن أمثلة لرموز العمل. فيما يلي بعض المكتبات ومكونات
Button
التي تم تنفيذها من خلال وسائلهما. تحتوي وثائق هذه المكتبات على أمثلة لاستخدام هذه المكونات. نحن نتحدث عن مكتبة شقرا ومكتبة رد الفعل الدلالي واجهة المستخدم.
الوثائق المكونة لشقرازر الدلالة واجهة المستخدم وثائق التوثيقهذا هو بالضبط ما نحتاجه. هذه أمثلة يمكن أن ندرسها لمعرفة استهلاكهم لموارد المعالج. يمكن العثور على أمثلة مماثلة في أحشاء الوثائق ، أو في التعليقات البرمجية المكتوبة بأسلوب JSDoc. ربما ، إذا كنت محظوظًا ، فستجد أمثلة من هذا القبيل ، مصممة كملفات منفصلة ، على سبيل المثال ، في شكل ملفات اختبار وحدة. بالتأكيد سيكون كذلك. بعد كل شيء ، نكتب جميعا اختبارات وحدة. حقا؟
ملفات
تخيل ، من أجل توضيح الطريقة الموضحة لتحليل الأداء ، أن هناك عنصر
Button
في المكتبة التي ندرسها ، والتي يوجد رمز لها في ملف
Button.js
. يتم
Button.js
الملف الذي يحتوي على اختبار وحدة
Button-test.js
بهذا الملف ، بالإضافة إلى ملف مع مثال لاستخدام المكون -
Button-example.js
. نحتاج إلى إنشاء نوع من صفحة الاختبار ، في بيئة يمكن تشغيل رمز الاختبار فيها. شيء من هذا القبيل
test.html
.
عنصر
هنا هو مكون
Button
بسيط. يمكنني استخدام React هنا ، ولكن يمكن كتابة مكوناتك باستخدام أي تقنية ملائمة لك.
import React from 'react'; const Button = (props) => props.href ? <a {...props} className="Button"/> : <button {...props} className="Button"/> export default Button;
مثال
وهنا مثال على استخدام مكون
Button
. كما ترى ، يوجد في هذه الحالة خياران للمكونات يستخدمان خصائص مختلفة.
import React from 'react'; import Button from 'Button'; export default [ <Button onClick={() => alert('ouch')}> Click me </Button>, <Button href="https://reactjs.com"> Follow me </Button>, ]
اختبار
فيما يلي صفحة
test.html
التي يمكنها تحميل أي مكونات. لاحظ استدعاء الأسلوب لكائن
performance
. بفضل مساعدتهم ، يمكننا ، بناءً على طلبنا ، الكتابة إلى ملف سجل أداء Chrome. قريبا جدا سوف نستخدم هذه السجلات.
const examples = await import(location.hash + '-example.js'); examples.forEach(example => performance.mark('my mark start'); ReactDOM.render(<div>{example}</div>, where); performance.mark('my mark end'); performance.measure( 'my mark', 'my mark start', 'my mark end'); );
اختبار عداء
من أجل تحميل صفحة اختبار في Chrome ، يمكننا استخدام مكتبة Puppeteer Node.js ، والتي تتيح لنا الوصول إلى واجهة برمجة التطبيقات لإدارة المتصفح. يمكنك استخدام هذه المكتبة على أي نظام تشغيل. يحتوي على نسخته الخاصة من Chrome ، ولكن يمكن استخدامه أيضًا للعمل مع مثيل من Chrome أو Chromium للإصدارات المختلفة الموجودة بالفعل على كمبيوتر المطور. يمكن تشغيل Chrome بحيث تكون النافذة غير مرئية. يتم إجراء الاختبارات تلقائيًا ، بينما لا يحتاج المطور إلى رؤية نافذة المتصفح. يمكن تشغيل Chrome في الوضع العادي. هذا مفيد لأغراض التصحيح.
فيما يلي مثال يتم تشغيل البرنامج النصي Node.js من سطر الأوامر الذي يقوم بتحميل صفحة اختبار وكتابة البيانات إلى ملف سجل الأداء. كل ما يحدث في المتصفح بين أوامر
tracing.start()
و
end()
مكتوب (أريد أن أشير ، بتفصيل كبير) إلى ملف
trace.json
.
import pup from 'puppeteer'; const browser = await pup.launch(); const page = await browser.newPage(); await page.tracing.start({path: 'trace.json'}); await page.goto('test.html#Button'); await page.tracing.stop(); await browser.close();
يمكن للمطور إدارة "تفاصيل" بيانات الأداء عن طريق تحديد "فئات" التتبع. يمكنك الاطلاع على قائمة الفئات المتاحة إذا انتقلت إلى Chrome على
chrome://tracing
، انقر فوق
Record
وفتح قسم
Edit categories
في النافذة التي تظهر.
تكوين تكوين البيانات المكتوبة في سجل الأداءالنتائج
بعد فحص صفحة الاختبار باستخدام Puppeteer ، يمكنك تحليل نتائج قياسات الأداء من خلال الانتقال إلى المتصفح على
chrome://tracing
وتنزيل ملف
trace.json
المسجل للتو.
Trace.json التصورهنا يمكنك رؤية نتائج استدعاء الأسلوب
performance.measure('my mark')
. استدعاء
measure()
مخصص لأغراض التصحيح فقط ، في حالة رغبة المطور في فتح ملف
trace.json
ورؤيته. يتم تضمين كل ما حدث مع الصفحة في كتلة
my mark
.
إليك
trace.json
:
جزء من ملف trace.jsonلمعرفة ما نحتاج إليه ، يكفي طرح مؤشر عدد إرشادات المعالج (
ticount
) الخاصة بعلامة
Start
من نفس المؤشر الخاص بعلامة
End
. يتيح لك ذلك معرفة عدد تعليمات المعالج المطلوبة لعرض المكون في المستعرض. هذا هو نفس الرقم الذي يمكنك استخدامه لمعرفة ما إذا كان المكون قد أصبح أسرع أو أبطأ.
الشيطان هو في التفاصيل
الآن قمنا بقياس المؤشرات التي تميز المخرجات الأولى فقط بصفحة مكون واحد. ولا شيء أكثر من ذلك. لا بد من قياس المؤشرات المتعلقة بأقل كمية من الشفرات التي يمكن تنفيذها. هذا يتيح لك تقليل مستوى الضوضاء. الشيطان هو في التفاصيل. أصغر يتم قياس الأداء ، كان ذلك أفضل. بعد القياسات ، من الضروري إزالة ما تم الحصول عليه من نتائج المطور من النتائج التي تم الحصول عليها. على سبيل المثال ، البيانات المتعلقة بعمليات جمع القمامة. المكون لا يتحكم في مثل هذه العمليات. إذا تم تنفيذها ، فهذا يعني أن المتصفح ، في عملية تقديم المكون ، قرر إطلاقه بنفسه. نتيجة لذلك ، يجب إزالة موارد المعالج التي ذهبت إلى مجموعة البيانات المهملة من النتائج النهائية.
يُطلق على كتلة البيانات المتعلقة بجمع البيانات المهملة (تسمى "كتلة البيانات" هذه "الحدث" بشكل صحيح) اسم
V8.GCScavenger
. ينبغي طرح
tidelta
من عدد تعليمات المعالج التي تدخل في جعل المكون.
إليك الوثائق الخاصة بأحداث التتبع. صحيح ، إنه قديم ولا يحتوي على معلومات حول المؤشرات التي نحتاجها:
tidelta
- عدد تعليمات المعالج المطلوبة لمعالجة الحدث.ticount
- عدد الإرشادات لبدء الحدث.
عليك أن تكون حذرا للغاية بشأن ما نقيسه. المتصفحات كيانات ذكية للغاية. انهم تحسين رمز الذي يعمل أكثر من مرة. في الرسم البياني التالي ، يمكنك رؤية عدد تعليمات المعالج اللازمة لإخراج مكون معين. تتطلب عملية التقديم الأولى أكبر قدر من الموارد. العمليات اللاحقة تخلق حمولة أقل بكثير على المعالج. يجب أن يؤخذ ذلك في الاعتبار عند تحليل أداء التعليمات البرمجية.
10 تقديم العمليات من نفس المكونفيما يلي تفاصيل أخرى: إذا كان المكون ينفذ بعض العمليات غير المتزامنة (على سبيل المثال ، فإنه يستخدم
setTimeout()
أو
fetch()
) ، فلن يؤخذ بالحمل على النظام الذي تم إنشاؤه بواسطة الكود غير المتزامن. ربما هذا جيد. ربما كان سيئا. إذا كنت تبحث عن أداء هذه المكونات ، ففكر في دراسة منفصلة للكود غير المتزامن.
إشارة قوية
إذا اتبعت مقاربة مسؤولة لحل مشكلة ما الذي يتم قياسه بالضبط ، فيمكنك الحصول على إشارة مستقرة حقًا تعكس التأثير على أداء أي تغييرات. أنا أحب نعومة الخطوط في الرسم البياني التالي.
نتائج القياس مستقرةيوضح الرسم البياني السفلي نتائج قياس 10 عمليات تجسيد لعنصر
<span>
بسيط في React. يتم تضمين أي شيء آخر في هذه النتائج. اتضح أن هذه العملية تتطلب من 2.15 إلى 2.2 مليون تعليمات المعالج. إذا قمت بلف
<span>
في علامة
<p>
، ثم لإخراج مثل هذا التصميم ، فإنك تحتاج إلى حوالي 2.3 مليون تعليمات. هذا المستوى من الدقة يضربني. إذا تمكن أحد المطورين من رؤية اختلاف الأداء الذي يظهر عند إضافة عنصر
<p>
فردي إلى الصفحة ، فهذا يعني أن المطور لديه أداة قوية حقًا في أيديهم.
كيف بالضبط لتمثيل قياسات هذه الدقة متروك للمطور. إذا لم يكن بحاجة إلى مثل هذه الدقة ، فيمكنه دائمًا قياس أداء عرض الأجزاء الكبيرة.
معلومات الأداء الإضافية
الآن بعد أن أصبح لدى المطور نظام تحت تصرفه لإيجاد مؤشرات رقمية تميز بدقة أداء أصغر أجزاء التعليمات البرمجية ، يمكن للمطور استخدام هذا النظام لحل المشكلات المختلفة. لذلك ، باستخدام
performance.mark()
يمكنك كتابة معلومات إضافية مفيدة إلى
trace.json
. يمكنك إخبار أعضاء فريق التطوير بما يحدث وما الذي يسبب زيادة في عدد تعليمات المعالج اللازمة لتنفيذ بعض التعليمات البرمجية. يمكنك تضمين معلومات تقارير الأداء حول عدد عقد DOM ، أو حول عدد عمليات الكتابة في DOM التي يتم تنفيذها بواسطة React. في الواقع ، هنا يمكنك عرض معلومات حول الكثير. يمكنك حساب عدد عمليات إعادة حساب تخطيط الصفحة. باستخدام Puppeteer ، يمكنك التقاط لقطات شاشة للصفحات ومقارنة مظهر الواجهة قبل إجراء التغييرات وبعدها. في بعض الأحيان تبدو الزيادة في عدد إرشادات المعالج اللازمة لعرض صفحة غير مفاجئة تمامًا. على سبيل المثال ، إذا تمت إضافة 10 أزرار و 12 حقلًا لتحرير النص وتنسيقه إلى الإصدار الجديد من الصفحة.
النتائج
هل من الممكن للجميع الذي تمت مناقشته هنا أن يستخدمه اليوم؟ نعم يمكنك ذلك. للقيام بذلك ، تحتاج إلى إصدار Chrome 78 أو أعلى. إذا كان لدى
ticount
tidelta
و
tidelta
، فسيكون ما سبق متاحًا لك. الإصدارات السابقة من Chrome لا تفعل ذلك.
لسوء الحظ ، لا يمكن الحصول على معلومات حول عدد تعليمات المعالج على النظام الأساسي لـ Mac. لم أجرب Windows حتى الآن ، لذلك لا أستطيع أن أقول أي شيء محدد حول نظام التشغيل هذا. بشكل عام - أصدقاؤنا يونكس ولينكس.
تجدر الإشارة إلى أنه لكي يتمكن المستعرض من توفير معلومات حول إرشادات المعالج ، ستحتاج إلى استخدام
--no-sandbox
- وهما
--no-sandbox
and
--enable-thread-instruction-count
إليك كيفية نقلها إلى متصفح تم تشغيله بواسطة Puppeteer:
await puppeteer.launch({ args: [ '--no-sandbox', '--enable-thread-instruction-count', ]});
، await puppeteer.launch({ args: [ '--no-sandbox', '--enable-thread-instruction-count', ]});
نأمل الآن أن تأخذ تحليل أداء تطبيق الويب الخاص بك إلى المستوى التالي.
أعزائي القراء! هل تخطط لاستخدام منهجية تحليل أداء مشاريع الويب المقدمة هنا؟
