ดูข้อมูลเบื้องต้นเกี่ยวกับการใช้ Navigation and Resource Timing API เพื่อประเมินประสิทธิภาพการโหลดในสนาม
เผยแพร่: 8 ตุลาคม 2021
หากเคยใช้การควบคุมปริมาณการเชื่อมต่อในแผงเครือข่ายในเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ของเบราว์เซอร์ (หรือ Lighthouse ใน Chrome) เพื่อประเมินประสิทธิภาพการโหลด คุณก็ทราบดีว่าเครื่องมือเหล่านี้สะดวกเพียงใดในการปรับแต่งประสิทธิภาพ คุณสามารถวัดผลลัพธ์ของการเพิ่มประสิทธิภาพได้อย่างรวดเร็วด้วยความเร็วการเชื่อมต่อพื้นฐานที่สอดคล้องกันและเสถียร ปัญหาเดียวก็คือการทดสอบแบบสังเคราะห์ซึ่งให้ผลลัพธ์ข้อมูลในห้องทดลอง ไม่ใช่ข้อมูลภาคสนาม
การทดสอบแบบสังเคราะห์ไม่ได้แย่โดยเนื้อแท้ แต่ไม่ได้แสดงถึงความเร็วในการโหลดเว็บไซต์สำหรับผู้ใช้จริง ซึ่งต้องใช้ข้อมูลภาคสนามที่คุณสามารถรวบรวมได้จาก Navigation Timing API และ Resource Timing API
API ที่ช่วยคุณประเมินประสิทธิภาพการโหลดในสนาม
การจับเวลาการนำทางและระยะเวลาการใช้ทรัพยากรเป็น API 2 ประเภทที่คล้ายกันซึ่งมีการซ้อนทับกันอย่างมีนัยสำคัญ ซึ่งจะวัด 2 สิ่งที่แตกต่างกันดังนี้
- เวลาในการนําทางจะวัดความเร็วของคําขอเอกสาร HTML (นั่นคือคําขอการนําทาง)
- การกำหนดเวลาของทรัพยากรจะวัดความเร็วของคำขอทรัพยากรที่ขึ้นอยู่กับเอกสาร เช่น CSS, JavaScript, รูปภาพ และทรัพยากรประเภทอื่นๆ
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 เหล่านี้ให้อาจดูเยอะเกินกว่าจะรับมือได้ แต่ข้อมูลเหล่านี้เป็นกุญแจสำคัญในการวัดประสิทธิภาพการโหลดในสนาม เนื่องจากคุณสามารถรวบรวมเวลาเหล่านี้จากผู้ใช้ขณะเข้าชมเว็บไซต์
ระยะเวลาและช่วงเวลาของคําขอเครือข่าย
การรวบรวมและวิเคราะห์เวลาในการนําทางและการใช้ทรัพยากรนั้นคล้ายกับโบราณคดีตรงที่คุณจะต้องสร้างใหม่จากสิ่งที่เกิดขึ้นแล้ว บางครั้งการเห็นภาพแนวคิดก็ช่วยได้ และในกรณีที่เกี่ยวข้องกับคำขอเครือข่าย เครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ของเบราว์เซอร์จะมีประโยชน์
วงจรชีวิตของคําขอเครือข่ายมีระยะที่แตกต่างกัน เช่น การค้นหา 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
จะทำเครื่องหมายเมื่อไคลเอ็นต์เริ่มการเจรจา TLSconnectEnd
คือเวลาที่สร้างการเชื่อมต่อกับเว็บเซิร์ฟเวอร์
การวัดเวลาการเชื่อมต่อทั้งหมดคล้ายกับการวัดเวลาในการค้นหา 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 เปอร์เซ็นต์หรือสูงกว่า แสดงว่าคุณกําลังมุ่งเน้นที่ประสบการณ์ที่ช้าที่สุด
คู่มือนี้ไม่ได้มีไว้เพื่อเป็นแหล่งข้อมูลที่ครอบคลุมเกี่ยวกับเวลาในการนําทางหรือเวลาในการตอบสนองของทรัพยากร แต่เป็นเพียงจุดเริ่มต้น แหล่งข้อมูลเพิ่มเติมที่อาจเป็นประโยชน์มีดังนี้
- ข้อกำหนดระยะเวลาในการนำทาง
- ข้อกําหนดการกําหนดเวลาของทรัพยากร
- ResourceTiming ในทางปฏิบัติ
- Navigation Timing API (MDN)
- Resource Timing API (MDN)
API เหล่านี้และข้อมูลที่ API ระบุจะช่วยให้คุณเข้าใจประสบการณ์ของผู้ใช้จริงเกี่ยวกับประสิทธิภาพการโหลดได้ดียิ่งขึ้น ซึ่งจะช่วยให้คุณมั่นใจมากขึ้นในการวินิจฉัยและแก้ไขปัญหาเกี่ยวกับประสิทธิภาพการโหลดในสนาม