المقاييس المخصّصة

هناك فائدة كبيرة من توفّر مقاييس تركّز على المستخدِم يمكنك قياسها بشكل عام على أيّ موقع إلكتروني معيّن. تتيح لك هذه المقاييس تنفيذ ما يلي:

  • فهم تجربة المستخدمين الفعليين على الويب ككل
  • قارِن موقعك الإلكتروني بموقع إلكتروني تابع لمنافس.
  • يمكنك تتبُّع البيانات المفيدة والقابلة للاستخدام في أدوات الإحصاءات بدون الحاجة إلى كتابة رموز مخصَّصة.

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

تتيح لك المقاييس المخصّصة قياس جوانب تجربة موقعك الإلكتروني التي قد تنطبق على موقعك فقط، مثل:

  • هي المدة التي يستغرقها انتقال تطبيق من صفحة واحدة (SPA) من "صفحة" إلى أخرى.
  • الوقت الذي تستغرقه الصفحة لعرض البيانات التي تم جلبها من قاعدة بيانات للمستخدمين الذين سجّلوا الدخول
  • المدة التي يستغرقها التطبيق المعروض من جهة الخادم (SSR) لترطيب
  • نسبة مرات الوصول إلى ذاكرة التخزين المؤقت للموارد التي حمّلها الزوّار المتكرّرون
  • وقت استجابة الحدث لأحداث النقر أو لوحة المفاتيح في لعبة.

واجهات برمجة التطبيقات لقياس المقاييس المخصّصة

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

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

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

Performance Observer API

توافق المتصفّح

  • Chrome: 52
  • ‫Edge: 79
  • Firefox: 57.
  • Safari: 11-

المصدر

واجهة برمجة التطبيقات Performance Observer API هي الآلية التي تجمع البيانات من جميع واجهات برمجة التطبيقات الأخرى المتعلّقة بالأداء والمذكورة في هذه الصفحة، وتعرضها. وفهمها أمر بالغ الأهمية للحصول على بيانات جيدة.

يمكنك استخدام 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 فقط.

ما لم تكن بحاجة إلى التوافق مع Internet Explorer على وجه التحديد، من الأفضل تجنُّب هذه الطرق في الرمز البرمجي واستخدام PerformanceObserver من الآن فصاعدًا.

User Timing API

توافق المتصفّح

  • Chrome: 28.
  • الحافة: 12.
  • Firefox: 38.
  • ‫Safari: 11

المصدر

User Timing 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

توافق المتصفّح

  • Chrome: 58
  • الحافة: 79.
  • Firefox: غير متوافق
  • Safari: غير متوافق

المصدر

يمكن الاستفادة من Long Tasks API في معرفة متى يتم حظر سلسلة المحادثات الرئيسية في المتصفّح لمدة طويلة بما يكفي للتأثير على عدد اللقطات في الثانية أو وقت استجابة الإدخال. ستحدّد واجهة برمجة التطبيقات أي مهام تستغرق أكثر من 50 ملي ثانية لتنفيذها.

في أي وقت تحتاج فيه إلى تنفيذ رمز برمجي مُكلّف أو تحميل نصوص برمجية كبيرة وتنفيذها، من المفيد تتبُّع ما إذا كان هذا الرمز البرمجي يحظر سلسلة التعليمات الرئيسية. في الواقع، يتم إنشاء العديد من المقاييس ذات المستوى الأعلى استنادًا إلى Long Tasks API نفسها (مثل وقت التفاعل (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

توافق المتصفّح

  • Chrome: 123.
  • الحافة: 123.
  • Firefox: غير متوافق
  • Safari: غير متاح.

المصدر

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 API

دعم المتصفح

  • Chrome: 77
  • ‫Edge: 79
  • Firefox: غير مدعوم.
  • Safari: غير متوافق

المصدر

يُعدّ مقياس سرعة عرض أكبر محتوى مرئي (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>

واجهة برمجة تطبيقات توقيت الحدث

دعم المتصفح

  • Chrome: 76
  • الحافة: 79.
  • Firefox: 89
  • Safari: غير متوافق

المصدر

يقيّم مقياس مدى استجابة الصفحة لتفاعلات المستخدم (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 API

توافق المتصفّح

  • Chrome: 29
  • Edge: 12.
  • Firefox: 35
  • ‫Safari: 11

المصدر

توفّر واجهة برمجة التطبيقات 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});

توافق المتصفّح

  • Chrome: 57
  • الحافة: 12.
  • Firefox: 58.
  • Safari: 15-

المصدر

تتشابه Navigation Timing API مع Resource Timing API، ولكنها لا تسجّل سوى طلبات التنقّل. يتشابه نوع الإدخال navigation أيضًا مع نوع الإدخال resource، ولكنّه يحتوي على بعض المعلومات الإضافية الخاصة بطلبات التنقّل فقط (مثل عند تنشيط الحدثَين DOMContentLoaded وload).

يتوفّر مقياس واحد يتتبّعه العديد من المطوّرين لفهم وقت استجابة الخادم (وقت وصول أول بايت (TTFB)) باستخدام واجهة برمجة التطبيقات Navigation Timing API، وهو الطابع الزمني 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

توافق المتصفّح

  • Chrome: 65
  • الحافة: 79.
  • Firefox: 61
  • ‫Safari: 16.4

المصدر

تتيح لك واجهة برمجة التطبيقات Server Timing API تمرير بيانات التوقيت الخاصة بالطلب من خادمك إلى المتصفّح من خلال رؤوس الاستجابة. على سبيل المثال، يمكنك الإشارة إلى المدة التي استغرقها البحث في البيانات في قاعدة بيانات لطلب معين - والتي يمكن أن تكون مفيدة في تصحيح أخطاء الأداء الناتجة عن بطء الخادم.

بالنسبة إلى المطوّرين الذين يستخدِمون مزوّدي خدمات إحصاءات خارجيين، فإنّ Server Timing API هي الطريقة الوحيدة لربط بيانات أداء الخادم بمقاييس النشاط التجاري الأخرى التي قد تقيسها أدوات الإحصاءات هذه.

لتحديد بيانات توقيت الخادم في ردودك، يمكنك استخدام عنوان الاستجابة Server-Timing. في ما يلي مثال:

HTTP/1.1 200 OK

Server-Timing: miss, db;dur=53, app;dur=47.2

بعد ذلك، يمكنك من صفحاتك قراءة هذه البيانات في كلّ من إدخالات resource أو navigation من واجهات برمجة التطبيقات Resource Timing وNavigation Timing API.

// 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});