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

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

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

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

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

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

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

واجهة برمجة تطبيقات Performance Monitorer

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

  • 52
  • 79
  • 57
  • 11

المصدر

واجهة برمجة التطبيقات Performance Monitorer هي الآلية التي تجمع البيانات وتعرضها من جميع واجهات برمجة تطبيقات الأداء الأخرى التي تمت مناقشتها في هذه الصفحة. إن فهم الأمر أمر بالغ الأهمية للحصول على بيانات جيدة.

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

عند إنشاء PerformanceObserver، يمكنك ضبط استدعاء يتم تشغيله كلما يتم إرسال إدخالات جديدة للأداء. بعد ذلك، استخدِم الطريقة observe() لإخبار المراقب بأنواع الإدخالات التي يجب الاستماع إليها على النحو التالي:

// Catch errors that some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  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'});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

تسرد الأقسام التالية جميع أنواع الإدخالات التي يمكنك ملاحظتها. في المتصفحات الأحدث، يمكنك أيضًا فحص أنواع الإدخالات المتاحة باستخدام السمة PerformanceObserver.supportedEntryTypes الثابتة.

ملاحظة الإدخالات التي حدثت بالفعل

وفقًا للإعدادات التلقائية، لا يمكن لكائنات PerformanceObserver سوى مراقبة الإدخالات عند حدوثها. ويمكن أن يتسبّب ذلك في حدوث مشاكل إذا كنت تريد استخدام التحميل الكسول لرمز تحليلات الأداء حتى لا يحظر الموارد ذات الأولوية الأعلى.

للحصول على الإدخالات السابقة، اتصل بـ observe مع ضبط علامة buffered على true. يتضمّن المتصفّح بعد ذلك الإدخالات السابقة من المورد الاحتياطي لإدخال الأداء في المرة الأولى التي يتم فيها استدعاء ميزة معاودة الاتصال في PerformanceObserver.

po.observe({
  type: 'some-entry-type',
  buffered: true,
});

واجهات برمجة تطبيقات الأداء القديمة التي يجب تجنبها

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

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

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

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" قياسات توقيت المستخدم في لوحة "الأداء"، ويتتبّع العديد من موفري خدمات التحليلات تلقائيًا أيّ قياسات تجريها ويرسلون بيانات المدة إلى خلفية الإحصاءات لديهم.

لإعداد تقارير عن قياسات User Timing، عليك تسجيل PerformanceObserver لمراقبة الإدخالات من النوع measure:

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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.
  po.observe({type: 'measure', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

واجهة برمجة تطبيقات "مهام Google" الطويلة

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

  • 58
  • 79
  • x
  • x

المصدر

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

في أي وقت تحتاج فيه إلى تشغيل رمز برمجي باهظ الثمن، أو تحميل نصوص برمجية كبيرة وتنفيذها، من المفيد تتبُّع ما إذا كانت هذه التعليمة البرمجية تحظر سلسلة التعليمات الرئيسية أم لا. في الواقع، يتم إنشاء العديد من المقاييس ذات المستوى الأعلى على واجهة برمجة التطبيقات Long Tasks API نفسها (مثل وقت التفاعل (TTI) وإجمالي وقت الحظر (TBT)).

لتحديد وقت تنفيذ المهام الطويلة، سجِّل أداة PerformanceObserver لتتبُّع الإدخالات من النوع longtask:

// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

واجهة برمجة تطبيقات Element Timing

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

  • 77
  • 79
  • x
  • x

المصدر

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

بالنسبة إلى هذه الحالات، يمكنك استخدام Element Timing API. تم إنشاء واجهة برمجة التطبيقات LCP API استنادًا إلى Element Timing API وتضيف تقارير تلقائية للعنصر الأكبر للمحتوى الذي يتضمن محتوًى، ولكن يمكنك أيضًا إعداد تقارير عن العناصر الأخرى من خلال إضافة السمة elementtiming إليها بشكل صريح وتسجيل أداة PerformanceMonitorer لملاحظة نوع الإدخال element.

<img elementtiming="hero-image" />
<p elementtiming="important-paragraph">This is text I care about.</p>
...
<script>
// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}
</script>

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

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

من الممكن باستخدام Event Timing API، بالإضافة إلى قياس FID، تعرض أيضًا عددًا من الطوابع الزمنية في دورة حياة الحدث، بما في ذلك:

  • startTime: الوقت الذي يتلقّى فيه المتصفّح الحدث
  • processingStart: الوقت الذي يمكن فيه للمتصفّح بدء معالجة معالِجات الأحداث للحدث.
  • processingEnd: الوقت الذي ينتهي فيه المتصفِّح من تنفيذ جميع الرموز المتزامنة التي بدأت من معالجات الأحداث لهذا الحدث.
  • duration: الوقت (يتم تقريبه إلى 8 ملّي ثانية لأسباب تتعلّق بالأمان) بين وقت تلقّي المتصفِّح للحدث إلى أن يتمكّن من عرض الإطار التالي بعد الانتهاء من تنفيذ جميع الرموز المتزامنة التي تم تشغيلها من معالِجات الأحداث.

يوضح المثال التالي كيفية استخدام هذه القيم لإنشاء مقاييس مخصّصة:

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  const po = new PerformanceObserver((entryList) => {
    const firstInput = entryList.getEntries()[0];

    // Measure First Input Delay (FID).
    const firstInputDelay = firstInput.processingStart - firstInput.startTime;

    // Measure the time it takes to run all event handlers
    // Doesn't include work scheduled asynchronously using methods like
    // `requestAnimationFrame()` or `setTimeout()`.
    const firstInputProcessingTime = firstInput.processingEnd - firstInput.processingStart;

    // Measure the entire duration of the event, from when input is received by
    // the browser until the next frame can be painted after processing all
    // event handlers.
    // Doesn't include work scheduled asynchronously using
    // `requestAnimationFrame()` or `setTimeout()`.
    // For security reasons, this value is rounded to the nearest 8 ms.
    const firstInputDuration = firstInput.duration;

    // Log these values to the console.
    console.log({
      firstInputDelay,
      firstInputProcessingTime,
      firstInputDuration,
    });
  });

  po.observe({type: 'first-input', buffered: true});
} catch (error) {
  // Do nothing if the browser doesn't support this API.
}

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

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

  • initiatorType: كيفية جلب المورد، مثلاً من علامة <script> أو <link> أو من fetch().
  • nextHopProtocol: البروتوكول المستخدَم لاسترجاع المورد، مثل h2 أو quic.
  • encodedBodySize وdecodedBodySize]: حجم المورد في شكله المشفر أو فك ترميزه (على التوالي).
  • transferSize: حجم المورد الذي تم نقله فعليًا عبر الشبكة. عند استيفاء الموارد باستخدام ذاكرة التخزين المؤقت، يمكن أن تكون هذه القيمة أصغر بكثير من encodedBodySize، وفي بعض الحالات يمكن أن تكون صفرًا، إذا لم تكن هناك حاجة إلى إعادة التحقّق من ذاكرة التخزين المؤقت.

يمكنك استخدام السمة transferSize لإدخالات توقيت الموارد لقياس مقياس معدّل نتيجة ذاكرة التخزين المؤقت أو مقياس إجمالي حجم الموارد المخزّنة مؤقتًا، وهو ما يفيد في فهم تأثير استراتيجية التخزين المؤقت للموارد في أداء الزوّار المتكرّرين.

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

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // If transferSize is 0, the resource was fulfilled via the cache.
      console.log(entry.name, entry.transferSize === 0);
    }
  });
  // Start listening for `resource` entries to be dispatched.
  po.observe({type: 'resource', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

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

  • 57
  • 12
  • 58
  • 15

المصدر

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

هناك مقياس يتتبّعه العديد من المطوّرين لفهم وقت استجابة الخادم، وهو مقياس الوقت المستغرق إلى أول بايت (TTFB)، وهو متاح من خلال الطابع الزمني responseStart في واجهة برمجة تطبيقات Navigation Timing.

// Catch errors since  browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

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

يمكن تحديد وقت بدء تشغيل مشغّل الخدمات لطلب تنقّل محدّد من منطقة دلتا بين entry.responseStart وentry.workerStart على النحو التالي:

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

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

تتيح لك 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 من واجهات برمجة تطبيقات توقيت الموارد وتوقيت التنقل.

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}