نحوه ارزیابی عملکرد بارگذاری در میدان با زمان‌بندی ناوبری و زمان‌بندی منابع

اصول اولیه استفاده از API های ناوبری و زمان بندی منابع را برای ارزیابی عملکرد بارگیری در محل بیاموزید.

منتشر شده: ۸ اکتبر ۲۰۲۱

اگر از قابلیت محدود کردن اتصال در پنل شبکه در ابزارهای توسعه‌دهندگان مرورگر (یا Lighthouse در کروم) برای ارزیابی عملکرد بارگذاری استفاده کرده باشید، می‌دانید که این ابزارها چقدر برای تنظیم عملکرد مناسب هستند. می‌توانید به سرعت تأثیر بهینه‌سازی‌های عملکرد را با یک سرعت اتصال پایه ثابت و پایدار اندازه‌گیری کنید. تنها مشکل این است که این یک آزمایش مصنوعی است که داده‌های آزمایشگاهی را ارائه می‌دهد، نه داده‌های میدانی .

آزمایش مصنوعی ذاتاً بد نیست، اما نمایانگر سرعت بارگذاری وب‌سایت شما برای کاربران واقعی نیست. این کار به داده‌های میدانی نیاز دارد که می‌توانید از APIهای زمان‌بندی ناوبری و زمان‌بندی منابع جمع‌آوری کنید.

APIهایی برای کمک به شما در ارزیابی عملکرد بارگیری در محل

زمان‌بندی ناوبری و زمان‌بندی منابع دو API مشابه با همپوشانی قابل توجه هستند که دو چیز متمایز را اندازه‌گیری می‌کنند:

  • زمان‌بندی ناوبری، سرعت درخواست‌ها برای اسناد HTML (یعنی درخواست‌های ناوبری) را اندازه‌گیری می‌کند.
  • زمان‌بندی منابع، سرعت درخواست‌ها برای منابع وابسته به سند مانند CSS، جاوا اسکریپت، تصاویر و سایر انواع منابع را اندازه‌گیری می‌کند.

این APIها داده‌های خود را در یک بافر ورودی عملکرد (performance entry buffer ) قرار می‌دهند که می‌توان با جاوا اسکریپت در مرورگر به آن دسترسی داشت. روش‌های مختلفی برای پرس‌وجو از بافر عملکرد وجود دارد، اما یک روش رایج استفاده از performance.getEntriesByType است:

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

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

performance.getEntriesByType رشته‌ای را می‌پذیرد که نوع ورودی‌هایی را که می‌خواهید از بافر ورودی عملکرد بازیابی کنید، توصیف می‌کند. 'navigation' و 'resource' به ترتیب زمان‌بندی‌های مربوط به APIهای Navigation Timing و Resource Timing را بازیابی می‌کنند.

حجم اطلاعاتی که این APIها ارائه می‌دهند می‌تواند بسیار زیاد باشد، اما آنها کلید شما برای اندازه‌گیری عملکرد بارگذاری در این زمینه هستند، زیرا می‌توانید این زمان‌بندی‌ها را از کاربران هنگام بازدید از وب‌سایت خود جمع‌آوری کنید.

طول عمر و زمان‌بندی یک درخواست شبکه

جمع‌آوری و تحلیل ناوبری و زمان‌بندی منابع، چیزی شبیه به باستان‌شناسی است، به این معنی که شما در حال بازسازی زندگی زودگذر یک درخواست شبکه پس از وقوع آن هستید. گاهی اوقات تجسم مفاهیم مفید است و در مورد درخواست‌های شبکه، ابزارهای توسعه‌دهنده مرورگر شما می‌توانند کمک کنند.

زمان‌بندی شبکه همانطور که در DevTools کروم نشان داده شده است. زمان‌بندی‌های نشان داده شده برای صف‌بندی درخواست، مذاکره اتصال، خود درخواست و پاسخ در نوارهای رنگی نشان داده شده است.
تجسم یک درخواست شبکه در پنل شبکه Chrome DevTools

چرخه عمر یک درخواست شبکه دارای مراحل مشخصی مانند جستجوی DNS، برقراری اتصال، مذاکره TLS و سایر منابع تأخیر است. این زمان‌بندی‌ها به صورت DOMHighResTimestamp نمایش داده می‌شوند. بسته به مرورگر شما، جزئیات زمان‌بندی‌ها ممکن است تا حد میکروثانیه باشد یا به میلی‌ثانیه گرد شود. شما باید این مراحل و نحوه ارتباط آنها با زمان‌بندی ناوبری و زمان‌بندی منابع را به طور مفصل بررسی کنید.

جستجوی DNS

وقتی کاربری به یک URL می‌رود، از سیستم نام دامنه (DNS) درخواست می‌شود تا دامنه را به آدرس IP تبدیل کند. این فرآیند ممکن است زمان قابل توجهی طول بکشد - زمانی که حتی می‌خواهید در محل اندازه‌گیری کنید. زمان‌بندی پیمایش و زمان‌بندی منابع دو زمان‌بندی مرتبط با DNS را نشان می‌دهند:

  • domainLookupStart زمانی است که جستجوی DNS آغاز می‌شود.
  • domainLookupEnd زمانی است که جستجوی DNS به پایان می‌رسد.

محاسبه کل زمان جستجوی DNS را می‌توان با کم کردن معیار شروع از معیار پایان انجام داد:

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

مذاکره اتصال

یکی دیگر از عوامل مؤثر در عملکرد بارگذاری، مذاکره اتصال است که تأخیری است که هنگام اتصال به یک وب سرور ایجاد می‌شود. اگر HTTPS درگیر باشد، این فرآیند شامل زمان مذاکره TLS نیز خواهد بود. مرحله اتصال شامل سه زمان‌بندی است:

  • connectStart زمانی است که مرورگر شروع به باز کردن اتصال به یک وب سرور می‌کند.
  • secureConnectionStart زمانی شروع می‌شود که کلاینت مذاکره TLS را آغاز کند.
  • connectEnd زمانی است که اتصال به وب سرور برقرار شده است.

اندازه‌گیری کل زمان اتصال مشابه اندازه‌گیری کل زمان جستجوی DNS است: شما زمان شروع را از زمان پایان کم می‌کنید. با این حال، یک ویژگی secureConnectionStart اضافی وجود دارد که اگر از HTTPS استفاده نشود یا اتصال پایدار باشد، ممکن است 0 باشد. اگر می‌خواهید زمان مذاکره 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;
}

پس از پایان جستجوی DNS و مذاکره برای اتصال، زمان‌بندی‌های مربوط به دریافت اسناد و منابع وابسته به آنها وارد عمل می‌شوند.

درخواست‌ها و پاسخ‌ها

عملکرد بارگیری تحت تأثیر دو نوع عامل قرار دارد:

  • عوامل بیرونی: اینها مواردی مانند تأخیر و پهنای باند هستند. فراتر از انتخاب یک شرکت میزبانی وب و احتمالاً یک CDN ، آنها (عمدتاً) از کنترل ما خارج هستند، زیرا کاربران می‌توانند از هر مکانی به وب دسترسی داشته باشند.
  • عوامل ذاتی: اینها مواردی مانند معماری سمت سرور و کلاینت و همچنین اندازه منابع و توانایی ما در بهینه‌سازی برای آن موارد هستند که تحت کنترل ما هستند.

هر دو نوع عامل بر عملکرد بارگیری تأثیر می‌گذارند. زمان‌بندی‌های مربوط به این عوامل حیاتی هستند، زیرا مدت زمان لازم برای دانلود منابع را توصیف می‌کنند. هم زمان‌بندی پیمایش و هم زمان‌بندی منابع، عملکرد بارگیری را با معیارهای زیر توصیف می‌کنند:

  • fetchStart زمانی را نشان می‌دهد که مرورگر شروع به دریافت یک منبع (زمان‌بندی منبع) یا یک سند برای یک درخواست ناوبری (زمان‌بندی ناوبری) می‌کند. این مرحله قبل از درخواست واقعی انجام می‌شود و نقطه‌ای است که مرورگر در حال بررسی حافظه‌های پنهان (به عنوان مثال، نمونه‌های HTTP و Cache ) است.
  • workerStart زمانی شروع به مدیریت یک درخواست در داخل رویداد fetch یک service worker می‌کند . این مقدار زمانی 0 خواهد بود که هیچ service worker صفحه فعلی را کنترل نکند.
  • 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 است. هر دو روش، درخواستی را به یک نقطه پایانی مشخص شده به روشی غیر مسدودکننده ارسال می‌کنند و درخواست به گونه‌ای در صف قرار می‌گیرد که در صورت نیاز، از جلسه صفحه فعلی بیشتر عمر کند:

// Check for navigator.sendBeacon support:
if ('sendBeacon' in navigator) {
  // 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());

  // Send the data!
  navigator.sendBeacon('/analytics', data);
}

در این مثال، رشته JSON به صورت یک payload POST ارسال می‌شود که می‌توانید آن را رمزگشایی، پردازش و در صورت نیاز در backend برنامه ذخیره کنید.

نتیجه‌گیری

وقتی معیارها را جمع‌آوری کردید، این به شما بستگی دارد که چگونه داده‌های میدانی را تجزیه و تحلیل کنید. هنگام تجزیه و تحلیل داده‌های میدانی، چند قانون کلی وجود دارد که باید رعایت کنید تا مطمئن شوید که به نتایج معناداری می‌رسید:

  • از میانگین‌ها اجتناب کنید ، زیرا آنها نماینده تجربه هیچ کاربر واحدی نیستند و ممکن است تحت تأثیر داده‌های پرت قرار گیرند.
  • به درصدها تکیه کنید. در مجموعه داده‌های معیارهای عملکرد مبتنی بر زمان، هرچه کمتر باشد بهتر است. این بدان معناست که وقتی درصدهای پایین را در اولویت قرار می‌دهید، فقط به سریع‌ترین تجربیات توجه می‌کنید.
  • اولویت‌بندی دنباله بلند ارزش‌ها . وقتی تجربیاتی را که در صدک ۷۵ یا بالاتر قرار دارند، اولویت‌بندی می‌کنید، تمرکز خود را روی جایی که باید باشد قرار می‌دهید: روی کندترین تجربیات.

این راهنما قرار نیست منبع جامعی در مورد ناوبری یا زمان‌بندی منابع باشد، بلکه یک نقطه شروع است. در اینجا چند منبع اضافی وجود دارد که ممکن است مفید باشند:

با استفاده از این APIها و داده‌هایی که ارائه می‌دهند، شما بهتر می‌توانید درک کنید که عملکرد بارگذاری توسط کاربران واقعی چگونه تجربه می‌شود، که به شما اطمینان بیشتری در تشخیص و رفع مشکلات عملکرد بارگذاری در محل می‌دهد.