การประเมินประสิทธิภาพการโหลดในฟิลด์ด้วย Navigation Timing และ Resource Timing

เรียนรู้ข้อมูลเบื้องต้นเกี่ยวกับการใช้ API การนำทางและระยะเวลาทรัพยากร เพื่อประเมินประสิทธิภาพการโหลดในฟิลด์

หากเคยใช้การควบคุมการเชื่อมต่อในแผงเครือข่ายในเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ของเบราว์เซอร์ (หรือ Lighthouse ใน Chrome) เพื่อประเมินประสิทธิภาพการโหลด แสดงว่าเครื่องมือเหล่านั้นใช้ได้สะดวกเพียงใดสำหรับการปรับแต่งประสิทธิภาพ คุณสามารถวัดผลของการเพิ่มประสิทธิภาพได้อย่างรวดเร็วด้วยความเร็วในการเชื่อมต่อพื้นฐานที่เสถียรและสม่ำเสมอ ปัญหาเดียวคือการทดสอบสังเคราะห์ ซึ่งจะให้ข้อมูลในห้องปฏิบัติการ ไม่ใช่ข้อมูลภาคสนาม

การทดสอบสังเคราะห์ไม่ได้ที่ไม่ดี แต่ไม่ได้แสดงถึงความเร็วที่เว็บไซต์โหลดสำหรับผู้ใช้จริง ซึ่งต้องใช้ข้อมูลฟิลด์ ซึ่งสามารถรวบรวมได้จาก Navigation Timing และ Resource Timing API

API ที่จะช่วยคุณประเมินประสิทธิภาพการโหลดในภาคสนาม

Navigation Timing และ Resource Timing เป็น API ที่คล้ายกัน 2 รายการและมีการทับซ้อนกันอย่างมากซึ่งวัด 2 สิ่งที่แตกต่างกัน ได้แก่

  • เวลาการนำทางจะวัดความเร็วของคำขอสำหรับเอกสาร HTML (นั่นคือคำขอการนำทาง)
  • ระยะเวลาของทรัพยากรจะวัดความเร็วของคำขอสำหรับทรัพยากรที่ขึ้นอยู่กับเอกสาร เช่น CSS, JavaScript, รูปภาพ และอื่นๆ

โดย API เหล่านี้จะเปิดเผยข้อมูลในบัฟเฟอร์รายการประสิทธิภาพ ซึ่งเข้าถึงได้ในเบราว์เซอร์ด้วย JavaScript คุณค้นหาบัฟเฟอร์ประสิทธิภาพได้หลายวิธี แต่วิธีที่ใช้กันโดยทั่วไปคือการใช้ performance.getEntriesByType ดังนี้

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

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

performance.getEntriesByType ยอมรับสตริงที่อธิบายประเภทของรายการที่คุณต้องการดึงจากบัฟเฟอร์รายการประสิทธิภาพ 'navigation' และ 'resource' จะดึงข้อมูลช่วงเวลาสำหรับ Navigation Timing และ Resource Timing API ตามลำดับ

ข้อมูลที่ API เหล่านี้ให้อาจมีมากเกินไป แต่ข้อมูลเหล่านี้คือกุญแจสำคัญในการวัดประสิทธิภาพการโหลดในภาคสนาม เนื่องจากคุณสามารถรวบรวมช่วงเวลาเหล่านี้จากผู้ใช้ขณะที่เข้าชมเว็บไซต์ของคุณ

อายุการใช้งานและระยะเวลาของคำขอเครือข่าย

การรวบรวมและการวิเคราะห์ช่วงเวลาของการนำทางและเวลาที่ทรัพยากรนั้นก็เหมือนกับโบราณคดี นั่นคือการทบทวนอายุการใช้งานของคำขอเครือข่ายที่ปรากฏอยู่ชั่วขณะ บางครั้งก็จะช่วยให้เห็นภาพแนวคิดและส่วนที่มีความกังวลเกี่ยวกับคำขอเครือข่าย เครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ของเบราว์เซอร์ก็ช่วยได้

แผนภาพเวลาของเครือข่ายตามที่แสดงในเครื่องมือสำหรับนักพัฒนาเว็บของ Chrome เวลาที่แสดงมีไว้สำหรับการจัดคิวคำขอ การเจรจาการเชื่อมต่อ ตัวคำขอเอง และการตอบสนองเป็นแถบที่มีโค้ดสี
ภาพคำขอเครือข่ายในแผงเครือข่ายของเครื่องมือสำหรับนักพัฒนาเว็บของ Chrome

ระยะเวลาของคำขอเครือข่ายมีช่วงเวลาที่แตกต่างกัน เช่น การค้นหา DNS, การสร้างการเชื่อมต่อ, การเจรจา TLS และอื่นๆ เวลาเหล่านี้จะแสดงเป็น DOMHighResTimestamp รายละเอียดของการจับเวลาอาจลดลงถึงไมโครวินาทีหรือปัดขึ้นเป็นมิลลิวินาที ทั้งนี้ขึ้นอยู่กับเบราว์เซอร์ของคุณ เรามาดูรายละเอียดของขั้นตอนเหล่านี้กัน และความเกี่ยวข้องกับ Navigation Timing และ Resource Timing

การค้นหา DNS

เมื่อผู้ใช้ไปที่ URL ระบบจะค้นหาระบบชื่อโดเมน (DNS) เพื่อแปลโดเมนเป็นที่อยู่ IP กระบวนการนี้อาจใช้เวลานาน คุณควรวัดในภาคสนามด้วยซ้ำ Navigation Timing และ Resource Timing แสดงการจับเวลาที่เกี่ยวข้องกับ DNS 2 รายการ ได้แก่

  • domainLookupStart คือเวลาที่การค้นหา DNS เริ่มต้น
  • domainLookupEnd คือเวลาที่การค้นหา DNS สิ้นสุดลง

การคำนวณเวลาในการค้นหา DNS ทั้งหมดคำนวณได้โดยลบเมตริกเริ่มต้นออกจากเมตริกสิ้นสุด ดังนี้

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

การต่อรองการเชื่อมต่อ

อีกปัจจัยหนึ่งที่มีผลต่อประสิทธิภาพการโหลดคือการเจรจาการเชื่อมต่อ ซึ่งเป็นเวลาในการตอบสนองที่เกิดขึ้นเมื่อเชื่อมต่อกับเว็บเซิร์ฟเวอร์ หากมีการใช้ HTTPS กระบวนการนี้จะรวมเวลาในการเจรจา TLS ด้วย ระยะการเชื่อมต่อประกอบด้วย 3 ช่วงเวลา ได้แก่

  • connectStart คือเวลาที่เบราว์เซอร์เริ่มเปิดการเชื่อมต่อกับเว็บเซิร์ฟเวอร์
  • secureConnectionStart จะทำเครื่องหมายเวลาที่ไคลเอ็นต์เริ่มต้นการเจรจา TLS
  • connectEnd คือเมื่อสร้างการเชื่อมต่อกับเว็บเซิร์ฟเวอร์

การวัดเวลาในการเชื่อมต่อทั้งหมดคล้ายกับการวัดเวลาในการค้นหา DNS ทั้งหมด โดยหักลบเวลาเริ่มต้นออกจากเวลาสิ้นสุด อย่างไรก็ตาม ยังมีพร็อพเพอร์ตี้ 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;
}

เมื่อการค้นหา DNS และการเจรจาการเชื่อมต่อสิ้นสุดลง เวลาที่เกี่ยวข้องกับการดึงข้อมูลเอกสารและทรัพยากรที่ต้องอาศัยกันจะมีผล

คำขอและการตอบกลับ

ปัจจัย 2 ประเภทส่งผลต่อประสิทธิภาพในการโหลด ได้แก่

  • ปัจจัยภายนอก: ได้แก่ เวลาในการตอบสนองและแบนด์วิดท์ นอกจากการเลือกบริษัทโฮสติ้งและ CDN แล้ว บริษัท (ส่วนใหญ่) ก็ไม่สามารถควบคุมได้ เนื่องจากผู้ใช้สามารถเข้าถึงเว็บได้จากทุกที่
  • ปัจจัยภายใน: ได้แก่ สถาปัตยกรรมของเซิร์ฟเวอร์และฝั่งไคลเอ็นต์ ตลอดจนขนาดทรัพยากรและความสามารถในการปรับแต่งเพื่อสิ่งต่างๆ เหล่านี้ ซึ่งอยู่ภายใต้การควบคุมของเรา

ปัจจัยทั้ง 2 ประเภทส่งผลต่อประสิทธิภาพการโหลด การจับเวลาที่เกี่ยวข้องกับปัจจัยเหล่านี้มีความสำคัญอย่างยิ่ง เนื่องจากอธิบายระยะเวลาที่ใช้ในการดาวน์โหลดทรัพยากร ทั้ง Navigation Timing และ Resource Timing จะอธิบายประสิทธิภาพของการโหลดด้วยเมตริกต่อไปนี้

  • fetchStart จะทำเครื่องหมายเมื่อเบราว์เซอร์เริ่มดึงข้อมูลทรัพยากร (Resource Timing) หรือเอกสารสำหรับคำขอการนำทาง (Navigation Timing) ข้อมูลนี้จะปรากฏก่อนคำขอจริง และเป็นจุดที่เบราว์เซอร์กำลังตรวจสอบแคช (เช่น 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;

การวัดอื่นๆ ที่คุณทำได้

Navigation Timing และ Resource Timing เป็นประโยชน์มากกว่าที่ตัวอย่างด้านบนสรุป สถานการณ์อื่นๆ เกี่ยวกับช่วงเวลาที่เกี่ยวข้องซึ่งคุณควรสำรวจมีดังนี้

  • การเปลี่ยนเส้นทางหน้าเว็บ: การเปลี่ยนเส้นทางเป็นแหล่งที่มาของเวลาในการตอบสนองที่เพิ่มเข้ามาซึ่งถูกมองข้ามไป โดยเฉพาะเชนการเปลี่ยนเส้นทาง เวลาในการตอบสนองเพิ่มขึ้นได้หลายวิธี เช่น การเปลี่ยนเส้นทาง HTTP-to-HTTP รวมถึงการเปลี่ยนเส้นทาง 302/uncached 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
});

วิธีรวบรวมช่วงเวลานี้อาจดูแปลกประหลาดเมื่อเทียบกับการเข้าถึงบัฟเฟอร์รายการประสิทธิภาพโดยตรง แต่ควรผูกเทรดหลักกับงานที่ไม่มีจุดประสงค์ที่สำคัญต่อผู้ใช้

บ้าน Phoning Home

เมื่อรวบรวมเวลาทั้งหมดที่ต้องการแล้ว คุณสามารถส่งข้อมูลดังกล่าวไปยังปลายทางเพื่อทำการวิเคราะห์เพิ่มเติมได้ โดยใช้ navigator.sendBeacon หรือ fetch ที่ตั้งค่าตัวเลือก keepalive ไว้ 2 วิธี ทั้ง 2 วิธีจะส่งคำขอไปยังปลายทางที่ระบุในแบบที่ไม่บล็อก และคำขอจะอยู่ในคิวในลักษณะที่ทำให้เซสชันหน้าปัจจุบันหมดลงแล้ว หากจำเป็น

// 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 ซึ่งคุณถอดรหัสและประมวลผล/จัดเก็บไว้ในแบ็กเอนด์ของแอปพลิเคชันได้ตามต้องการ

ใกล้จะเสร็จแล้ว

เมื่อคุณรวบรวมเมตริกแล้ว คุณจะต้องหาวิธีวิเคราะห์ข้อมูลภาคสนามนั้น เมื่อวิเคราะห์ข้อมูลภาคสนาม มีกฎทั่วไป 2-3 ข้อที่ต้องปฏิบัติตามเพื่อให้แน่ใจว่าคุณจะได้ข้อสรุปที่มีความหมาย

  • หลีกเลี่ยงค่าเฉลี่ย เนื่องจากไม่ได้แสดงถึงประสบการณ์ของผู้ใช้ใดๆ และอาจบิดเบือนโดยค่าผิดปกติ
  • พึ่งพาเปอร์เซ็นไทล์ ในชุดข้อมูลของเมตริกประสิทธิภาพที่อิงตามเวลา ยิ่งน้อยยิ่งดี ซึ่งหมายความว่าเมื่อให้ความสำคัญกับเปอร์เซ็นต์ไทล์ที่ต่ำ จะเป็นการให้ความสำคัญกับประสบการณ์ที่เร็วที่สุดเท่านั้น
  • จัดลำดับความสำคัญด้านยาวของค่า เมื่อให้ความสำคัญกับประสบการณ์ที่เปอร์เซ็นไทล์ที่ 75 ขึ้นไป เท่ากับว่าคุณให้ความสำคัญกับเรื่องนั้น นั่นคือประสบการณ์ที่ช้าที่สุด

คำแนะนำนี้ไม่ได้เป็นเพียงแหล่งข้อมูลอย่างละเอียดเกี่ยวกับการนำทางหรือระยะเวลาของทรัพยากร แต่เป็นจุดเริ่มต้น แหล่งข้อมูลเพิ่มเติมบางส่วนที่อาจเป็นประโยชน์กับคุณมีดังนี้

คุณจะใช้ API เหล่านี้และข้อมูลที่มีให้ได้ดีขึ้นเพื่อทำความเข้าใจประสิทธิภาพการโหลดของผู้ใช้จริงให้ดียิ่งขึ้น ซึ่งจะเพิ่มความมั่นใจในการวินิจฉัยและแก้ไขปัญหาเกี่ยวกับประสิทธิภาพการโหลดในภาคสนามได้มากขึ้น