يمكنك الاستفادة بشكل كبير من استخدام مقاييس تركّز على المستخدم يمكنك قياسها على أي موقع إلكتروني محدّد بشكل عام. تتيح لك هذه المقاييس ما يلي:
- فهم كيف يجري المستخدمون تجربة الويب ككل.
- قارن موقعك بموقع إلكتروني منافس.
- يمكنك تتبُّع البيانات المفيدة والقابلة للاستخدام في أدوات الإحصاءات بدون الحاجة إلى كتابة رموز مخصَّصة.
توفّر المقاييس العامة مرجعًا جيدًا، ولكن عليك في كثير من الحالات قياس أكثر من هذه المقاييس فقط لتسجيل التجربة الكاملة لموقعك الإلكتروني المحدَّد.
تتيح لك المقاييس المخصّصة قياس جوانب تجربة موقعك الإلكتروني التي قد تنطبق على موقعك الإلكتروني فقط، مثل:
- المدة التي يستغرقها انتقال تطبيق من صفحة واحدة (SPA) من "صفحة" واحدة إلى آخر.
- هي المدة التي تستغرقها الصفحة لعرض البيانات التي تم استرجاعها من قاعدة بيانات للمستخدمين الذين سجّلوا دخولهم.
- المدة التي يستغرقها التطبيق المعروض من جهة الخادم (SSR) لترطيب
- معدَّل نتائج ذاكرة التخزين المؤقت للموارد التي حمَّلها الزوّار المكرّرو الزيارة.
- وقت استجابة الأحداث الناتجة من النقر أو أحداث لوحة المفاتيح في لعبة معيّنة
واجهات برمجة التطبيقات لقياس المقاييس المخصّصة
في السابق، لم يكن لدى مطوّري البرامج على الويب العديد من واجهات برمجة التطبيقات المنخفضة المستوى لقياس الأداء، وبالتالي كان عليهم اللجوء إلى عمليات الاختراق لقياس ما إذا كان أداء الموقع الإلكتروني جيدًا.
على سبيل المثال، من الممكن تحديد ما إذا كانت سلسلة التعليمات الرئيسية محظورة بسبب مهام JavaScript طويلة الأمد من خلال تشغيل حلقة requestAnimationFrame
وحساب الدلتا بين كل إطار. إذا كانت الدلتا أطول بكثير من معدل عرض إطارات الشاشة، يمكنك الإبلاغ عن ذلك كمهمة طويلة. مع ذلك، لا يُنصح بتنفيذ عمليات الاختراق هذه لأنّها تؤثر في الأداء نفسه (مثلاً، من خلال استنزاف البطارية).
تتمثل القاعدة الأولى لقياس الأداء الفعّال في التأكّد من أن أساليب قياس الأداء لا تتسبب في حدوث مشاكل في الأداء في حد ذاتها. لذا بالنسبة إلى أي مقاييس مخصّصة تقيسها على موقعك الإلكتروني، من الأفضل استخدام إحدى واجهات برمجة التطبيقات التالية إن أمكن.
واجهة برمجة تطبيقات مراقبة الأداء
إنّ واجهة برمجة تطبيقات "مراقبة الأداء" هي الآلية التي تجمع البيانات وتعرضها من جميع واجهات برمجة تطبيقات الأداء الأخرى التي تمت مناقشتها في هذه الصفحة. إن فهم ذلك أمر بالغ الأهمية للحصول على بيانات جيدة.
يمكنك استخدام PerformanceObserver
للاشتراك بشكل سلبي في الأحداث ذات الصلة بالأداء. ويسمح هذا بتنشيط طلبات معاودة الاتصال من واجهة برمجة التطبيقات خلال فترات عدم النشاط، ما يعني أنّها لن تتداخل عادةً مع أداء الصفحة.
لإنشاء PerformanceObserver
، أرسِل استدعاء ليتم تشغيله كلما تم إرسال إدخالات أداء جديدة. بعد ذلك تُطلع المراقب على أنواع الإدخالات التي يجب الاستماع إليها باستخدام طريقة observe()
:
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
po.observe({type: 'some-entry-type'});
تسرد الأقسام التالية جميع أنواع الإدخالات المختلفة المتاحة لملاحظتها، ولكن في المتصفّحات الأحدث، يمكنك فحص أنواع الإدخالات المتاحة من خلال السمة PerformanceObserver.supportedEntryTypes
الثابتة.
ملاحظة الإدخالات التي حدثت بالفعل
وفقًا للإعدادات التلقائية، يمكن لكائنات PerformanceObserver
مراقبة الإدخالات فقط عند حدوثها. ويمكن أن يتسبب ذلك في حدوث مشاكل إذا أردت التحميل الكسول لرمز إحصاءات الأداء، حتى لا يتم حظر الموارد ذات الأولوية الأعلى.
للحصول على الإدخالات السابقة (بعد حدوثها)، اضبط علامة buffered
على true
عند الاتصال بـ observe()
. سيتضمن المتصفِّح الإدخالات السابقة من المخزن المؤقت لإدخال الأداء في المرة الأولى التي يتم فيها استدعاء ميزة PerformanceObserver
حتى الحد الأقصى لحجم المخزن المؤقت لهذا النوع.
po.observe({
type: 'some-entry-type',
buffered: true,
});
واجهات برمجة التطبيقات القديمة للأداء التي يجب تجنّبها
قبل واجهة برمجة تطبيقات Performance Observer API، كان بإمكان المطوّرين الوصول إلى إدخالات الأداء باستخدام الطرق الثلاث التالية المحدَّدة في عنصر performance
:
ومع أنّ واجهات برمجة التطبيقات هذه ما زالت متوافقة، لا يُنصح باستخدامها لأنّها لا تتيح لك الانتباه عند إصدار إدخالات جديدة. بالإضافة إلى ذلك، لا يتم عرض العديد من واجهات برمجة التطبيقات الجديدة (مثل largest-contentful-paint
) من خلال الكائن performance
، ولا يتم عرضها إلا من خلال PerformanceObserver
.
لذا، من الأفضل تجنُّب هذه الطرق في الرمز واستخدام PerformanceObserver
من الآن فصاعدًا، ما لم تكن بحاجة إلى التوافق مع Internet Explorer على وجه التحديد.
واجهة برمجة تطبيقات توقيت المستخدم
User Timing API هي واجهة برمجة تطبيقات عامة. Measurement API للمقاييس المستندة إلى الوقت يتيح لك تحديد النقاط بشكل عشوائي الوقت ثم نقيس المدة بين هذه العلامات لاحقًا.
// Record the time immediately before running a task.
performance.mark('myTask:start');
await doMyTask();
// Record the time immediately after running a task.
performance.mark('myTask:end');
// Measure the delta between the start and end of the task
performance.measure('myTask', 'myTask:start', 'myTask:end');
على الرغم من أنّ واجهات برمجة التطبيقات مثل Date.now()
أو performance.now()
توفّر إمكانيات مشابهة، تكمن فائدة استخدام User Timing API في أنّها تندمج بشكل جيد مع أدوات الأداء. على سبيل المثال، تعرض "أدوات مطوري البرامج في Chrome" قياسات وقت المستخدم في لوحة الأداء، وسيتتبّع العديد من مقدّمي خدمات الإحصاءات تلقائيًا أي قياسات تجريها ويرسلون بيانات المدة إلى الواجهة الخلفية للإحصاءات.
للإبلاغ عن قياسات "وقت المستخدم"، يمكنك استخدام PerformanceObserver والتسجيل لمراقبة الإدخالات من النوع measure
:
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `measure` entries to be dispatched.
po.observe({type: 'measure', buffered: true});
واجهة برمجة تطبيقات "مهام طويلة"
يمكن الاستفادة من Long Tasks API في معرفة متى يتم حظر سلسلة المحادثات الرئيسية في المتصفّح لمدة طويلة بما يكفي للتأثير على عدد اللقطات في الثانية أو وقت استجابة الإدخال. ستبلغ واجهة برمجة التطبيقات عن أي مهام يتم تنفيذها لمدة تزيد عن 50 مللي ثانية.
عندما تحتاج إلى تشغيل رمز مكلف أو تحميل نصوص برمجية كبيرة وتنفيذها، من المفيد تتبُّع ما إذا كانت هذه الرمز تحظر سلسلة التعليمات الرئيسية. وفي الواقع، يتم إنشاء العديد من المقاييس ذات المستوى الأعلى في واجهة برمجة تطبيقات Long Tasks نفسها (مثل وقت التفاعل (TTI) وإجمالي وقت الحظر (TBT)).
لتحديد وقت حدوث المهام الطويلة، يمكنك استخدام PerformanceObserver والتسجيل لمراقبة الإدخالات من النوع longtask
:
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `longtask` entries to be dispatched.
po.observe({type: 'longtask', buffered: true});
واجهة برمجة تطبيقات Long Animation Frames
واجهة برمجة التطبيقات Long Animation Frames API هي نسخة جديدة من واجهة برمجة تطبيقات Long Tasks API التي تفحص الإطارات الطويلة، بدلاً من المهام الطويلة، التي تزيد مدتها عن 50 ملّي ثانية. يعالج ذلك بعض أوجه القصور في واجهة Long Tasks API، بما في ذلك تحسين عملية تحديد المصدر والنطاق الأوسع للتأخيرات التي يُحتمل أن تكون مسببة للمشاكل.
لتحديد وقت حدوث اللقطات الطويلة، يمكنك استخدام PerformanceObserver والتسجيل لمراقبة الإدخالات من النوع long-animation-frame
:
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `long-animation-frame` entries to be dispatched.
po.observe({type: 'long-animation-frame', buffered: true});
واجهة برمجة تطبيقات Element Timing
يُعدّ مقياس سرعة عرض أكبر محتوى مرئي (LCP) مفيدًا لمعرفة الوقت الذي تم فيه عرض أكبر صورة أو مقطع نصي على الشاشة، ولكن تريد في بعض الحالات قياس مدة عرض عنصر مختلف.
وبالنسبة إلى هذه الحالات، استخدِم Element Timing API. تم إنشاء واجهة LCP API في أعلى واجهة Element Timing API، وهي تضيف ميزة إعداد التقارير التلقائية عن المحتوى الذي يضم أكبر عدد ممكن من المحتوى، ولكن يمكنك أيضًا إعداد تقارير عن العناصر الأخرى من خلال إضافة سمة elementtiming
بوضوح إليها وتسجيل PerformanceObserver لتتبُّع نوع الإدخال element
.
<img elementtiming="hero-image" />
<p elementtiming="important-paragraph">This is text I care about.</p>
<!-- ... -->
<script>
const po = new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `element` entries to be dispatched.
po.observe({type: 'element', buffered: true});
</script>
واجهة برمجة تطبيقات توقيت الحدث
يقيّم مقياس مدى استجابة الصفحة لتفاعلات المستخدم (INP) مدى استجابة الصفحة بشكل عام من خلال رصد جميع تفاعلات النقر والنقر ولوحة المفاتيح على مدار الصفحة. غالبًا ما يكون مقياس INP للصفحة هو التفاعل الذي استغرق وقتًا أطول حتى يكتمل، بدءًا من الوقت الذي بدأ فيه المستخدم التفاعل، وحتى وقت رسم المتصفّح للإطار التالي الذي يعرض النتيجة المرئية لإدخال المستخدم.
أصبح مقياس INP ممكنًا من خلال Event Timing API. تعرض واجهة برمجة التطبيقات هذه عددًا من الطوابع الزمنية التي تحدث خلال مراحل الحدث، بما في ذلك:
startTime
: الوقت الذي يتلقّى فيه المتصفّح الحدثprocessingStart
: الوقت الذي يتمكّن فيه المتصفّح من بدء معالجة معالِجات الأحداث للحدثprocessingEnd
: الوقت الذي ينتهي فيه المتصفّح من تنفيذ جميع الرموز المتزامنة التي بدأت من معالِجات الأحداث لهذا الحدثduration
: الوقت (التقريب إلى 8 ملي ثانية لأسباب أمنية) بين وقت استلام المتصفّح للحدث إلى أن يتمكّن من عرض الإطار التالي بعد الانتهاء من تنفيذ كل الرموز البرمجية المتزامنة التي بدأت من معالِجات الأحداث.
يوضّح المثال التالي كيفية استخدام هذه القيم لإنشاء قياسات مخصّصة:
const po = new PerformanceObserver((entryList) => {
// Get the last interaction observed:
const entries = Array.from(entryList.getEntries()).forEach((entry) => {
// Get various bits of interaction data:
const inputDelay = entry.processingStart - entry.startTime;
const processingTime = entry.processingEnd - entry.processingStart;
const presentationDelay = entry.startTime + entry.duration - entry.processingEnd;
const duration = entry.duration;
const eventType = entry.name;
const target = entry.target || "(not set)"
console.log("----- INTERACTION -----");
console.log(`Input delay (ms): ${inputDelay}`);
console.log(`Event handler processing time (ms): ${processingTime}`);
console.log(`Presentation delay (ms): ${presentationDelay}`);
console.log(`Total event duration (ms): ${duration}`);
console.log(`Event type: ${eventType}`);
console.log(target);
});
});
// A durationThreshold of 16ms is necessary to include more
// interactions, since the default is 104ms. The minimum
// durationThreshold is 16ms.
po.observe({type: 'event', buffered: true, durationThreshold: 16});
واجهة برمجة تطبيقات Resource Timing
توفّر Resource Timing API للمطوّرين إحصاءات تفصيلية عن كيفية تحميل موارد صفحة معيَّنة. على الرغم من اسم واجهة برمجة التطبيقات، إنّ المعلومات التي تقدّمها لا تقتصر فقط على بيانات التوقيت (على الرغم من أنّ الكثير منها). وتشمل البيانات الأخرى التي يمكنك الوصول إليها ما يلي:
initiatorType
: طريقة جلب المرجع: مثل معلومات من علامة<script>
أو<link>
أو من مكالمةfetch()
.nextHopProtocol
: البروتوكول المستخدَم لجلب المورد، مثلh2
أوquic
encodedBodySize
/decodedBodySize]: حجم المورد في شكله المشفَّر أو الذي تم فك ترميزه (على التوالي)transferSize
: حجم المورد الذي تم نقله بالفعل عبر الشبكة. عند تنفيذ ذاكرة التخزين المؤقت للموارد، يمكن أن تكون هذه القيمة أصغر بكثير من قيمة "encodedBodySize
" وفي بعض الحالات يمكن أن تصبح صفرًا (إذا لم تكن هناك حاجة إلى إعادة التحقّق من ذاكرة التخزين المؤقت).
يمكنك استخدام السمة transferSize
لإدخالات توقيت الموارد لقياس مقياس معدل نتائج ذاكرة التخزين المؤقت أو مقياس إجمالي حجم الموارد المخزّنة مؤقتًا، ما قد يكون مفيدًا في معرفة مدى تأثير استراتيجية التخزين المؤقت للموارد في أداء الزوّار المتكرّرين.
يسجل المثال التالي جميع الموارد التي تطلبها الصفحة ويوضح ما إذا كانت ذاكرة التخزين المؤقت قد نفذت كل مورد أم لا.
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// If transferSize is 0, the resource was fulfilled using the cache.
console.log(entry.name, entry.transferSize === 0);
}
});
// Start listening for `resource` entries to be dispatched.
po.observe({type: 'resource', buffered: true});
واجهة برمجة تطبيقات وقت التنقل
تشبه واجهة برمجة تطبيقات وقت التنقل واجهة برمجة تطبيقات Resource Timing، ولكنها تُبلغ فقط عن طلبات التنقل. يتشابه نوع الإدخال navigation
أيضًا مع نوع الإدخال resource
، ولكنّه يحتوي على بعض المعلومات الإضافية الخاصة بطلبات التنقّل فقط (مثل عند تنشيط الحدثَين DOMContentLoaded
وload
).
يتوفّر مقياس واحد يتتبّعه العديد من المطوّرين لفهم وقت استجابة الخادم (وقت استجابة الخادم (TTFB)) باستخدام واجهة برمجة تطبيقات توقيت التنقل، وتحديدًا الطابع الزمني responseStart
للإدخال.
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// If transferSize is 0, the resource was fulfilled using the cache.
console.log('Time to first byte', entry.responseStart);
}
});
// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});
مقياس آخر قد يهتم به مطوِّرو الخدمات الذين يستخدمون مشغّل الخدمات هو وقت بدء تشغيل عامل الخدمة لطلبات التنقّل. يشير ذلك إلى الوقت الذي يستغرقه المتصفّح لبدء سلسلة مشغّل الخدمات قبل أن يبدأ في اعتراض أحداث الاسترجاع.
يمكن تحديد وقت بدء تشغيل مشغّل الخدمات لطلب تنقُّل معيَّن من الدلتا بين entry.responseStart
وentry.workerStart
.
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log('Service Worker startup time:',
entry.responseStart - entry.workerStart);
}
});
// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});
واجهة برمجة تطبيقات وقت الخادم
تتيح لك Server Timing API تمرير بيانات التوقيت المحدّدة للطلب من الخادم إلى المتصفّح من خلال عناوين الاستجابة. على سبيل المثال، يمكنك الإشارة إلى المدة التي استغرقها البحث في البيانات في قاعدة بيانات لطلب معين - والتي يمكن أن تكون مفيدة في تصحيح أخطاء الأداء الناتجة عن بطء الخادم.
بالنسبة إلى مطوّري البرامج الذين يستعينون بمقدّمي خدمة إحصاءات تابعين لجهات خارجية، تمثّل واجهة برمجة التطبيقات Server Timing الطريقة الوحيدة لربط بيانات أداء الخادم بمقاييس الأنشطة التجارية الأخرى التي قد تقيسها أدوات الإحصاءات هذه.
لتحديد بيانات توقيت الخادم في ردودك، يمكنك استخدام عنوان الاستجابة Server-Timing
. إليك مثالاً.
HTTP/1.1 200 OK
Server-Timing: miss, db;dur=53, app;dur=47.2
بعد ذلك، من صفحاتك، يمكنك قراءة هذه البيانات عن كلٍّ من إدخالات resource
أو navigation
من واجهات برمجة تطبيقات Resource Timing و Navigation Timing.
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Logs all server timing data for this response
console.log('Server Timing', entry.serverTiming);
}
});
// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});