تقييم أداء التحميل في الحقل من خلال توقيت التنقل وتوقيت المورد

تعرّف على أساسيات استخدام واجهات برمجة تطبيقات "التنقل" و"توقيت الموارد" لتقييم أداء التحميل في الحقل.

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

ليس الاختبار الاصطناعي سيئًا بطبيعتها، ولكنه لا يعكس مدى سرعة تحميل المستخدمين على موقعك الإلكتروني. يتطلب هذا بيانات حقل يمكنك جمعها من واجهات برمجة تطبيقات وقت التنقل وتوقيت الموارد.

واجهات برمجة التطبيقات لمساعدتك على تقييم أداء التحميل في الحقل

وقت التنقل وتوقيت المورد هما واجهتان برمجة تطبيقات مشابهتان مع تداخل كبير يقيس شيئين مختلفين:

  • يقيس وقت التنقل سرعة طلبات مستندات HTML (أي طلبات التنقل).
  • يقيس توقيت الموارد سرعة طلبات الموارد التي تعتمد على المستندات مثل CSS وJavaScript والصور وما إلى ذلك.

تعرض واجهات برمجة التطبيقات هذه بياناتها في مخزن مؤقت لإدخال الأداء يمكن الوصول إليه في المتصفّح باستخدام JavaScript. هناك عدة طرق للاستعلام عن المخزن المؤقت للأداء، ولكن الطريقة الشائعة هي استخدام performance.getEntriesByType:

// Get Navigation Timing entries:
performance.getEntriesByType('navigation');

// Get Resource Timing entries:
performance.getEntriesByType('resource');

تقبل الدالة performance.getEntriesByType سلسلة تصف نوع الإدخالات التي تريد استردادها من المخزن المؤقت لإدخال الأداء. يسترد 'navigation' و'resource' توقيتات واجهات برمجة تطبيقات وقت التنقل وتوقيت الموارد على التوالي.

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

مدة طلب الشبكة وتوقيتاته

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

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

تتسم مدة طلب الشبكة بمراحل مختلفة، مثل البحث في نظام أسماء النطاقات وإنشاء الاتصال والتفاوض بشأن بروتوكول أمان طبقة النقل (TLS) وما إلى ذلك. يتم عرض هذه التوقيتات على شكل DOMHighResTimestamp. واعتمادًا على المتصفح الذي تستخدمه، قد تقل دقة التوقيتات إلى الميكرو ثانية أو يتم تقريبها إلى مللي ثانية. دعنا نفحص هذه المراحل بالتفصيل، وكيفية ارتباطها بوقت التنقل وتوقيت المورد.

بحث نظام أسماء النطاقات

عندما ينتقل مستخدم إلى عنوان URL، يتم الاستعلام عن نظام أسماء النطاقات (DNS) لترجمة نطاق إلى عنوان IP. قد تستغرق هذه العملية وقتًا كبيرًا - الوقت الذي ستحتاج إلى قياسه في هذا المجال، حتى. يعرض توقيت التنقل وتوقيت المورد توقيتين مرتبطين بنظام أسماء النطاقات:

  • domainLookupStart هو عند بدء بحث نظام أسماء النطاقات.
  • domainLookupEnd هو عند انتهاء بحث نظام أسماء النطاقات.

يمكن حساب إجمالي وقت بحث نظام أسماء النطاقات بطرح مقياس البدء من مقياس النهاية:

// Measuring DNS lookup time
const [pageNav] = performance.getEntriesByType('navigation');
const totalLookupTime = pageNav.domainLookupEnd - pageNav.domainLookupStart;

التفاوض على الربط

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

  • connectStart هو عندما يبدأ المتصفِّح في فتح اتصال بخادم ويب.
  • يحدِّد secureConnectionStart الوقت الذي يبدأ فيه العميل تفاوض بروتوكول أمان طبقة النقل (TLS).
  • connectEnd هي عندما يتم إنشاء الاتصال بخادم الويب.

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

// Quantifying total connection time
const [pageNav] = performance.getEntriesByType('navigation');
const connectionTime = pageNav.connectEnd - pageNav.connectStart;
let tlsTime = 0; // <-- Assume 0 to start with

// Was there TLS negotiation?
if (pageNav.secureConnectionStart > 0) {
  // Awesome! Calculate it!
  tlsTime = pageNav.connectEnd - pageNav.secureConnectionStart;
}

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

الطلبات والردود

يتأثر أداء التحميل بنوعين من العوامل:

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

يؤثر كلا النوعين من العوامل في أداء التحميل. تُعتبر التوقيتات ذات الصلة بهذه العوامل مهمة للغاية لأنّها تصف الوقت الذي يستغرقه تنزيل الموارد. يصف كل من توقيت التنقل وتوقيت المورد أداء التحميل بالمقاييس التالية:

  • يحدد fetchStart الوقت الذي يبدأ فيه المتصفح في جلب مورد (توقيت الموارد) أو مستند لطلب تنقّل (وقت التنقل). يسبق الطلب الفعلي، وهي النقطة التي يتحقّق فيها المتصفّح من ذاكرات التخزين المؤقت (على سبيل المثال، مثيل HTTP وCache).
  • يحدِّد workerStart وقت بدء معالجة طلب ضمن معالج أحداث fetch لمشغِّل الخدمات. ستكون هذه القيمة 0 عندما لا يتحكّم أي مشغّل خدمات في الصفحة الحالية.
  • وrequestStart هو عندما يُجري المتصفِّح الطلب.
  • يحدث responseStart عند وصول البايت الأول من الاستجابة.
  • تظهر علامة responseEnd عندما يصل البايت الأخير من الرد.

وتتيح لك هذه التوقيتات قياس جوانب متعدّدة من أداء التحميل، مثل بحث ذاكرة التخزين المؤقت ضمن مشغّل خدمات ووقت التنزيل:

// Cache seek plus response time of the current document
const [pageNav] = performance.getEntriesByType('navigation');
const fetchTime = pageNav.responseEnd - pageNav.fetchStart;

// Service worker time plus response time
let workerTime = 0;

if (pageNav.workerStart > 0) {
  workerTime = pageNav.responseEnd - pageNav.workerStart;
}

يمكنك أيضًا قياس الجوانب الأخرى لوقت استجابة الطلب/الاستجابة:

const [pageNav] = performance.getEntriesByType('navigation');

// Request time only (excluding redirects, DNS, and connection/TLS time)
const requestTime = pageNav.responseStart - pageNav.requestStart;

// Response time only (download)
const responseTime = pageNav.responseEnd - pageNav.responseStart;

// Request + response time
const requestResponseTime = pageNav.responseEnd - pageNav.requestStart;

قياسات أخرى يمكنك إجراؤها

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

  • عمليات إعادة توجيه الصفحات: تُعدّ عمليات إعادة التوجيه مصدرًا مهملاً لوقت الاستجابة الإضافي، ولا سيما سلاسل إعادة التوجيه. تتم إضافة وقت الاستجابة بعدة طرق، مثل قفزات HTTP إلى HTTP، بالإضافة إلى عمليات إعادة التوجيه 302 أو عمليات إعادة التوجيه 301 غير المخزنة مؤقتًا. تساعد التوقيتات redirectStart وredirectEnd وredirectCount في تقييم وقت استجابة إعادة التوجيه.
  • إلغاء تحميل المستند: في الصفحات التي تشغِّل الرمز في معالج أحداث unload، يجب أن ينفِّذ المتصفّح هذا الرمز قبل أن يتمكن من الانتقال إلى الصفحة التالية. يقيس unloadEventStart وunloadEventEnd عملية إلغاء تحميل المستند.
  • معالجة المستندات: قد لا يكون وقت معالجة المستندات ذا تأثير ما لم يرسل موقعك الإلكتروني حمولات HTML كبيرة جدًا. إذا كان هذا يصف حالتك، قد يهمّك استخدام التوقيتات domInteractive وdomContentLoadedEventStart وdomContentLoadedEventEnd وdomComplete.

معرفة التوقيتات في رمز التطبيق

تستخدِم جميع الأمثلة المعروضة حتى الآن السمة performance.getEntriesByType، ولكن هناك طرق أخرى لطلب البحث عن المخزن المؤقت لإدخال الأداء، مثل performance.getEntriesByName وperformance.getEntries. هذه الطرق جيدة عند الحاجة إلى تحليل خفيف فقط. ومع ذلك، في حالات أخرى، قد يُفرِط في العمل على سلسلة التعليمات الرئيسية من خلال تكرار عدد كبير من الإدخالات أو حتى إجراء استطلاع متكرر للمخزن المؤقت للأداء للعثور على إدخالات جديدة.

والأسلوب المقترَح لجمع الإدخالات من المورد الاحتياطي لإدخال الأداء هو استخدام PerformanceObserver. يستمع PerformanceObserver إلى إدخالات الأداء، ويوفّرها عند إضافتها إلى المخزن المؤقت:

// Create the performance observer:
const perfObserver = new PerformanceObserver((observedEntries) => {
  // Get all resource entries collected so far:
  const entries = observedEntries.getEntries();

  // Iterate over entries:
  for (let i = 0; i < entries.length; i++) {
    // Do the work!
  }
});

// Run the observer for Navigation Timing entries:
perfObserver.observe({
  type: 'navigation',
  buffered: true
});

// Run the observer for Resource Timing entries:
perfObserver.observe({
  type: 'resource',
  buffered: true
});

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

اتصال هاتفي إلى المنزل

بمجرد الانتهاء من جمع كل التوقيتات التي تحتاجها، يمكنك إرسالها إلى نقطة نهاية لإجراء المزيد من التحليل. وهناك طريقتان لإجراء ذلك، وهما navigator.sendBeacon أو fetch مع ضبط خيار keepalive. وستُرسِل كلتا الطريقتين طلبًا إلى نقطة نهاية محدَّدة بطريقة لا تؤدي إلى الحظر، وسيتم وضع الطلب في قائمة الانتظار بطريقة تؤدي إلى انتهاء جلسة الصفحة الحالية عند الحاجة:

// Caution: If you have lots of performance entries, don't
// do this. This is an example for illustrative purposes.
const data = JSON.stringify(performance.getEntries()));

// The endpoint to transmit the encoded data to
const endpoint = '/analytics';

// Check for fetch keepalive support
if ('keepalive' in Request.prototype) {
  fetch(endpoint, {
    method: 'POST',
    body: data,
    keepalive: true,
    headers: {
      'Content-Type': 'application/json'
    }
  });
} else if ('sendBeacon' in navigator) {
  // Use sendBeacon as a fallback
  navigator.sendBeacon(endpoint, data);
}

في هذا المثال، ستصل سلسلة JSON في حمولة بيانات POST يمكنك فك ترميزها ومعالجتها/تخزينها في خلفية التطبيق حسب الحاجة.

ملخص

بمجرد جمع المقاييس، الأمر متروك لك لمعرفة كيفية تحليل بيانات هذا المجال. عند تحليل البيانات الميدانية، هناك بعض القواعد العامة التي يجب اتباعها لضمان استخلاص استنتاجات ذات مغزى:

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

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

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