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

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

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

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

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

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

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

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

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

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

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

دعم المتصفح

  • 52
  • 79
  • 57
  • 11

المصدر

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

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

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

// Catch errors since 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 مراقبة الإدخالات فقط عند حدوثها. ويمكن أن يتسبب ذلك في حدوث مشاكل إذا أردت التحميل الكسول لرمز إحصاءات الأداء، حتى لا يتم حظر الموارد ذات الأولوية الأعلى.

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

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

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

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

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

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

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

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:

// 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 `measure` entries to be dispatched.
  po.observe({type: 'measure', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

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

دعم المتصفح

  • 58
  • 79
  • x
  • x

المصدر

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

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

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

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

أصبح مقياس INP ممكنًا من خلال Event Timing API. تعرض واجهة برمجة التطبيقات هذه عددًا من الطوابع الزمنية التي تحدث خلال مراحل الحدث، بما في ذلك:

  • 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) => {
    // 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 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 time (ms): ${processingTime}`);
      console.log(`Total event duration (ms): ${duration}`);
      console.log(`Event type: ${eventType}`);
      console.log(target);
    });
  });

  // A durationThreshold of 16ms is necessary to surface more
  // interactions, since the default is 104ms. The minimum
  // durationThreshold is 16ms.
  po.observe({type: 'event', buffered: true, durationThreshold: 16});
} catch (error) {
  // Do nothing if the browser doesn't support this API.
}

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

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

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

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

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

// 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()) {
      // 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

المصدر

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

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

// 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()) {
      // If transferSize is 0, the resource was fulfilled via 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 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()) {
      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 الطريقة الوحيدة لربط بيانات أداء الخادم بمقاييس الأنشطة التجارية الأخرى التي قد تقيسها أدوات الإحصاءات هذه.

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

HTTP/1.1 200 OK

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

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

// 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()) {
      // 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.
}