วิธีประเมินประสิทธิภาพการโหลดในการใช้งานจริงด้วยระยะเวลาในการนําทางและระยะเวลาของทรัพยากร

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

เผยแพร่: 8 ตุลาคม 2021

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

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

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

การจับเวลาการนำทางและระยะเวลาการใช้ทรัพยากรเป็น API 2 ประเภทที่คล้ายกันซึ่งมีการซ้อนทับกันอย่างมีนัยสำคัญ ซึ่งจะวัด 2 สิ่งที่แตกต่างกันดังนี้

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

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

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

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

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

ระยะเวลาและช่วงเวลาของคําขอเครือข่าย

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

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

วงจรชีวิตของคําขอเครือข่ายมีระยะที่แตกต่างกัน เช่น การค้นหา DNS การสร้างการเชื่อมต่อ การเจรจา TLS และแหล่งที่มาอื่นๆ ของเวลาในการตอบสนอง ช่วงเวลาเหล่านี้จะแสดงเป็น DOMHighResTimestamp ความละเอียดของเวลาอาจแสดงเป็นไมโครวินาทีหรือปัดเศษเป็นมิลลิวินาที ทั้งนี้ขึ้นอยู่กับเบราว์เซอร์ที่ใช้ คุณควรตรวจสอบระยะเหล่านี้โดยละเอียด และดูว่าระยะเหล่านี้เกี่ยวข้องกับเวลาในการนําทางและเวลาในการตอบสนองของทรัพยากรอย่างไร

การค้นหา DNS

เมื่อผู้ใช้ไปที่ URL ระบบจะค้นหาระบบชื่อโดเมน (DNS) เพื่อแปลงโดเมนเป็นที่อยู่ IP กระบวนการนี้อาจใช้เวลานานพอสมควร ซึ่งคุณอาจต้องวัดผลในสนามด้วย ระยะเวลาในการนําทางและระยะเวลาของทรัพยากรจะแสดงระยะเวลาที่เกี่ยวข้องกับ 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 ประเภทส่งผลต่อประสิทธิภาพการโหลด การกำหนดเวลาที่เกี่ยวข้องกับปัจจัยเหล่านี้มีความสำคัญ เนื่องจากจะอธิบายระยะเวลาที่ใช้ในการดาวน์โหลดทรัพยากร ทั้งระยะเวลาในการนําทางและระยะเวลาของทรัพยากรจะอธิบายประสิทธิภาพการโหลดด้วยเมตริกต่อไปนี้

  • fetchStart หมายถึงเวลาที่เบราว์เซอร์เริ่มดึงข้อมูลทรัพยากร (เวลาในการตอบสนองของทรัพยากร) หรือดึงข้อมูลเอกสารสําหรับคําขอไปยังส่วนต่างๆ (เวลาในการตอบสนองในการนําทาง) ค่านี้เกิดขึ้นก่อนคำขอจริง และเป็นจุดที่เบราว์เซอร์ตรวจสอบแคช (เช่น อินสแตนซ์ HTTP และCache)
  • workerStart หมายถึงเวลาที่ระบบเริ่มจัดการคําขอภายในfetch event handler ของ Service Worker ค่านี้จะเท่ากับ 0 เมื่อไม่มี Service Worker ควบคุมหน้าปัจจุบัน
  • requestStart คือเวลาที่เบราว์เซอร์ส่งคําขอ
  • responseStart คือเมื่อไบต์แรกของการตอบกลับมาถึง
  • responseEnd คือเวลาที่ไบต์สุดท้ายของการตอบกลับมาถึง

การวัดเวลาเหล่านี้ช่วยให้คุณวัดประสิทธิภาพการโหลดได้หลายด้าน เช่น การค้นหาแคชภายใน Service Worker และเวลาในการดาวน์โหลด

// 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;

การวัดผลอื่นๆ ที่คุณสามารถทำได้

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

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

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

วิธีโทรหาบ้าน

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

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

บทสรุป

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

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

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

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