การมีเมตริกที่เน้นผู้ใช้เป็นศูนย์กลางนั้นมีประโยชน์มากมาย ซึ่งคุณสามารถวัดค่าต่างๆ ได้ในทุกเว็บไซต์ เมตริกเหล่านี้ช่วยให้คุณทำสิ่งต่อไปนี้ได้
- ทำความเข้าใจว่าผู้ใช้จริงได้รับประสบการณ์โดยรวมเว็บอย่างไร
- เปรียบเทียบเว็บไซต์ของคุณกับของคู่แข่ง
- ติดตามข้อมูลที่เป็นประโยชน์และนำไปปฏิบัติได้ในเครื่องมือการวิเคราะห์ของคุณโดยไม่ต้องเขียนโค้ดที่กำหนดเอง
เมตริกสากลเป็นเกณฑ์พื้นฐานที่ดี แต่ในหลายกรณี คุณจะต้องวัดมากกว่าเมตริกเหล่านี้เพื่อให้สามารถเก็บประสบการณ์การใช้งานที่สมบูรณ์สำหรับเว็บไซต์หนึ่งๆ ได้
เมตริกที่กำหนดเองช่วยให้คุณวัดแง่มุมต่างๆ ของประสบการณ์การใช้งานเว็บไซต์ที่อาจมีผลกับเว็บไซต์ของคุณเท่านั้น เช่น
- ระยะเวลาที่แอปแบบหน้าเดียว (SPA) เปลี่ยนจาก "หน้า" 1 หน้า ไปที่อีกแห่งหนึ่ง
- เวลาที่หน้าเว็บใช้ในการแสดงข้อมูลที่ดึงมาจากฐานข้อมูลสำหรับผู้ใช้ที่เข้าสู่ระบบ
- ระยะเวลาที่แอปที่แสดงผลฝั่งเซิร์ฟเวอร์ (SSR) ใช้ในการเพิ่มปริมาณ
- อัตราการพบแคชสำหรับทรัพยากรที่โหลดโดยผู้เข้าชมที่กลับมา
- เวลาในการตอบสนองของเหตุการณ์ของเหตุการณ์การคลิกหรือแป้นพิมพ์ในเกม
API สำหรับวัดเมตริกที่กำหนดเอง
ที่ผ่านมา นักพัฒนาเว็บไม่ค่อยมี API ระดับต่ำมากนักในการวัดประสิทธิภาพ และด้วยเหตุนี้ พวกเขาจึงต้องหันมาพึ่งการแฮ็กเพื่อวัดว่าเว็บไซต์ทำงานได้ดีหรือไม่
ตัวอย่างเช่น อาจเป็นไปได้ว่าเทรดหลักถูกบล็อกเนื่องจากงาน JavaScript ที่ใช้เวลานานหรือไม่ โดยการเรียกใช้ลูป requestAnimationFrame
และคำนวณเดลต้าระหว่างแต่ละเฟรม หากเดลต้ายาวกว่าอัตราเฟรมของจอแสดงผลอย่างมาก คุณก็รายงานว่าเป็นงานที่ใช้เวลานานได้ อย่างไรก็ตาม เราไม่แนะนำให้ทำการแฮ็กดังกล่าว เนื่องจากจริงๆ แล้วการทำเช่นนี้ส่งผลกระทบต่อประสิทธิภาพโดยตรง (เช่น ทำให้แบตเตอรี่หมดเร็ว)
กฎข้อแรกของการวัดประสิทธิภาพที่มีประสิทธิภาพคือการตรวจสอบว่าเทคนิคการวัดประสิทธิภาพของคุณไม่ได้ทำให้เกิดปัญหาด้านประสิทธิภาพ ดังนั้นสำหรับเมตริกที่กำหนดเองที่คุณวัดในเว็บไซต์ เราขอแนะนำให้ใช้ API อย่างใดอย่างหนึ่งต่อไปนี้หากเป็นไปได้
API เครื่องมือสังเกตประสิทธิภาพ
Performance Observer API คือกลไกที่รวบรวมและแสดงข้อมูลจาก API ด้านประสิทธิภาพอื่นๆ ทั้งหมดที่กล่าวถึงในหน้านี้ การเข้าใจเรื่องนี้จึงสำคัญอย่างยิ่งต่อการได้รับข้อมูลที่ดี
คุณสามารถใช้ PerformanceObserver
เพื่อสมัครรับข้อมูลกิจกรรมที่เกี่ยวข้องกับประสิทธิภาพได้แบบไม่ต้องทำอะไร ซึ่งจะทำให้ API Callback เริ่มทำงานในช่วงที่ไม่มีการใช้งาน ซึ่งหมายความว่าโดยปกติแล้วจะไม่รบกวนประสิทธิภาพของหน้าเว็บ
หากต้องการสร้าง PerformanceObserver
ให้ส่งผ่าน Callback เพื่อเรียกใช้ทุกครั้งที่มีการส่งรายการด้านประสิทธิภาพใหม่ จากนั้นให้บอกผู้สังเกตการณ์ว่าจะฟังรายการประเภทใดโดยใช้เมธอด observe()
ดังนี้
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
po.observe({type: 'some-entry-type'});
ส่วนต่อไปนี้จะแสดงรายการประเภทต่างๆ ทั้งหมดที่ดูได้ แต่จะตรวจสอบประเภทรายการที่ใช้ได้ผ่านพร็อพเพอร์ตี้ PerformanceObserver.supportedEntryTypes
แบบคงที่ในเบราว์เซอร์รุ่นใหม่
สังเกตรายการที่เกิดขึ้นแล้ว
โดยค่าเริ่มต้น ออบเจ็กต์ PerformanceObserver
รายการจะสังเกตการณ์ได้เฉพาะรายการที่เกิดขึ้นเท่านั้น วิธีนี้อาจทำให้เกิดปัญหาในกรณีที่คุณต้องการโหลดโค้ดการวิเคราะห์ประสิทธิภาพแบบ Lazy Loading เพื่อไม่ให้บล็อกทรัพยากรที่มีลำดับความสำคัญสูงกว่า
หากต้องการดูรายการข้อมูลในอดีต (หลังจากเกิดขึ้นแล้ว) ให้ตั้งค่าแฟล็ก buffered
เป็น true
เมื่อเรียกใช้ observe()
เบราว์เซอร์จะรวมรายการที่ผ่านมาจากบัฟเฟอร์รายการประสิทธิภาพในครั้งแรกที่มีการเรียก PerformanceObserver
Callback โดยไม่เกินขนาดบัฟเฟอร์สูงสุดสำหรับประเภทนั้น
po.observe({
type: 'some-entry-type',
buffered: true,
});
API ประสิทธิภาพเดิมที่ควรหลีกเลี่ยง
ก่อนที่จะใช้ Performance Observer API นักพัฒนาแอปจะเข้าถึงรายการประสิทธิภาพได้โดยใช้ 3 วิธีต่อไปนี้ซึ่งระบุไว้ในออบเจ็กต์ performance
แม้ว่าระบบจะยังรองรับ API เหล่านี้อยู่ แต่เราไม่แนะนำให้ใช้เนื่องจาก API จะไม่อนุญาตให้คุณคอยฟังเมื่อมีการเผยแพร่รายการใหม่ นอกจากนี้ API ใหม่จำนวนมาก (เช่น largest-contentful-paint
) ไม่แสดงผ่านออบเจ็กต์ performance
แต่จะแสดงผ่าน PerformanceObserver
เท่านั้น
คุณควรหลีกเลี่ยงวิธีการเหล่านี้ในโค้ดและใช้ PerformanceObserver
นับจากนี้เป็นต้นไป ยกเว้นกรณีที่คุณต้องการความเข้ากันได้กับ Internet Explorer
API ระยะเวลาของผู้ใช้
User Timing API เป็นวัตถุประสงค์ทั่วไป Measurement API สำหรับเมตริกตามเวลา ทำให้คุณสามารถทำเครื่องหมายคะแนนใน แล้ววัดระยะเวลาระหว่างเครื่องหมายเหล่านั้นในภายหลัง
// Record the time immediately before running a task.
performance.mark('myTask:start');
await doMyTask();
// Record the time immediately after running a task.
performance.mark('myTask:end');
// Measure the delta between the start and end of the task
performance.measure('myTask', 'myTask:start', 'myTask:end');
แม้ว่า API อย่าง Date.now()
หรือ performance.now()
จะให้ความสามารถที่คล้ายกัน แต่ข้อดีของการใช้ User Timing API คือสามารถผสานรวมกับเครื่องมือด้านประสิทธิภาพได้อย่างดี ตัวอย่างเช่น Chrome DevTools จะแสดงภาพการวัดระยะเวลาของผู้ใช้ในแผงประสิทธิภาพ และผู้ให้บริการวิเคราะห์หลายรายจะติดตามการวัดผลที่คุณสร้างโดยอัตโนมัติและส่งข้อมูลระยะเวลาไปยังแบ็กเอนด์การวิเคราะห์ของตน
ในการรายงานการวัดระยะเวลาของผู้ใช้ คุณสามารถใช้ PerformanceObserver และลงทะเบียนเพื่อสังเกตรายการประเภท measure
ดังนี้
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `measure` entries to be dispatched.
po.observe({type: 'measure', buffered: true});
API ของงานที่ใช้เวลานาน
Long Tasks API มีประโยชน์ในการช่วยให้ทราบเมื่อเทรดหลักของเบราว์เซอร์ถูกบล็อกเป็นเวลานานพอที่จะส่งผลต่ออัตราเฟรมหรือเวลาในการตอบสนองของอินพุต API จะรายงานงานที่ดำเนินการนานกว่า 50 มิลลิวินาที
เมื่อใดก็ตามที่คุณต้องเรียกใช้โค้ดราคาแพง หรือโหลดและเรียกใช้สคริปต์ขนาดใหญ่ การติดตามว่าโค้ดดังกล่าวจะบล็อกเทรดหลักหรือไม่ อันที่จริงแล้ว เมตริกระดับสูงจำนวนมากสร้างขึ้นจาก Long Tasks API เอง (เช่น Time to Interactive (TTI) และ Total Blocked Time (TBT))
ในการพิจารณาว่าจะมีงานที่ใช้เวลานานเกิดขึ้นเมื่อใด คุณสามารถใช้ PerformanceObserver และลงทะเบียนเพื่อติดตามรายการประเภท longtask
ดังต่อไปนี้
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `longtask` entries to be dispatched.
po.observe({type: 'longtask', buffered: true});
API เฟรมของภาพเคลื่อนไหวแบบยาว
Long Animation Frames API เป็นการปรับปรุงใหม่ของ Long Tasks API ซึ่งจะพิจารณาเฟรมขนาดยาว แทนที่จะเป็นงานที่ใช้เวลานานกว่า 50 มิลลิวินาที วิธีการนี้ช่วยแก้ไขข้อบกพร่องบางอย่างของ Long Tasks API ซึ่งรวมถึงการระบุแหล่งที่มาที่ดีขึ้นและขอบเขตที่กว้างขึ้นของความล่าช้าที่อาจเกิดขึ้นได้
ในการพิจารณาว่าเฟรมแบบยาวเกิดขึ้นเมื่อใด คุณสามารถใช้ PerformanceObserver และลงทะเบียนเพื่อสังเกตรายการของประเภท long-animation-frame
ดังนี้
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `long-animation-frame` entries to be dispatched.
po.observe({type: 'long-animation-frame', buffered: true});
Element Timing API
เมตริกการแสดงผลเนื้อหาขนาดใหญ่ที่สุด (LCP) มีประโยชน์ในการดูว่าเมื่อใดที่ระบายสีรูปภาพหรือบล็อกข้อความขนาดใหญ่ที่สุดไปยังหน้าจอ แต่ในบางกรณีคุณอาจต้องการวัดเวลาการแสดงผลขององค์ประกอบอื่น
สำหรับกรณีเหล่านี้ ให้ใช้ Element Timing API ที่จริงแล้ว LCP API สร้างขึ้นบน Element Timing API และเพิ่มการรายงานอัตโนมัติสําหรับองค์ประกอบที่มีเนื้อหาขนาดใหญ่ที่สุด แต่คุณยังสามารถรายงานเกี่ยวกับองค์ประกอบอื่นๆ ได้โดยเพิ่มแอตทริบิวต์ elementtiming
ลงในองค์ประกอบเหล่านั้นอย่างชัดเจน และลงทะเบียน PerformanceObserver เพื่อดูประเภทรายการ element
<img elementtiming="hero-image" />
<p elementtiming="important-paragraph">This is text I care about.</p>
<!-- ... -->
<script>
const po = new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `element` entries to be dispatched.
po.observe({type: 'element', buffered: true});
</script>
API ระยะเวลาเหตุการณ์
เมตริก Interaction to Next Paint (INP) จะประเมินการตอบสนองของหน้าเว็บโดยรวมโดยสังเกตการโต้ตอบกับการคลิก การแตะ และแป้นพิมพ์ทั้งหมดตลอดอายุของหน้าเว็บ INP ของหน้าเว็บมักเป็นการโต้ตอบที่ใช้เวลาดำเนินการนานที่สุด นับตั้งแต่เวลาที่ผู้ใช้เริ่มการโต้ตอบ ไปจนถึงตอนที่เบราว์เซอร์วาดเฟรมถัดไปซึ่งแสดงผลอินพุตของผู้ใช้แบบเป็นภาพ
เมตริก INP สร้างขึ้นโดย Event Timing API API นี้จะแสดงการประทับเวลาจำนวนหนึ่งที่เกิดขึ้นระหว่างวงจรของเหตุการณ์ ซึ่งรวมถึงเหตุการณ์ต่อไปนี้
startTime
: เวลาที่เบราว์เซอร์ได้รับเหตุการณ์processingStart
: เวลาที่เบราว์เซอร์เริ่มประมวลผลเครื่องจัดการเหตุการณ์ของเหตุการณ์นั้นได้processingEnd
: เวลาที่เบราว์เซอร์ดำเนินการโค้ดแบบซิงโครนัสทั้งหมดที่เริ่มต้นจากเครื่องจัดการเหตุการณ์สำหรับเหตุการณ์นี้เสร็จสิ้นduration
: เวลา (ปัดเศษเป็น 8 มิลลิวินาทีเพื่อความปลอดภัย) ระหว่างที่เบราว์เซอร์ได้รับเหตุการณ์จนกระทั่งสามารถวาดเฟรมถัดไปหลังจากเรียกใช้โค้ดแบบซิงโครนัสทั้งหมดที่เริ่มต้นจากเครื่องจัดการเหตุการณ์เสร็จแล้ว
ตัวอย่างต่อไปนี้แสดงวิธีใช้ค่าเหล่านี้เพื่อสร้างการวัดที่กําหนดเอง
const po = new PerformanceObserver((entryList) => {
// Get the last interaction observed:
const entries = Array.from(entryList.getEntries()).forEach((entry) => {
// Get various bits of interaction data:
const inputDelay = entry.processingStart - entry.startTime;
const processingTime = entry.processingEnd - entry.processingStart;
const presentationDelay = entry.startTime + entry.duration - entry.processingEnd;
const duration = entry.duration;
const eventType = entry.name;
const target = entry.target || "(not set)"
console.log("----- INTERACTION -----");
console.log(`Input delay (ms): ${inputDelay}`);
console.log(`Event handler processing time (ms): ${processingTime}`);
console.log(`Presentation delay (ms): ${presentationDelay}`);
console.log(`Total event duration (ms): ${duration}`);
console.log(`Event type: ${eventType}`);
console.log(target);
});
});
// A durationThreshold of 16ms is necessary to include more
// interactions, since the default is 104ms. The minimum
// durationThreshold is 16ms.
po.observe({type: 'event', buffered: true, durationThreshold: 16});
API การจับเวลาของทรัพยากร
Resource Timing API ทำให้นักพัฒนาแอปมีข้อมูลเชิงลึกโดยละเอียดว่ามีการโหลดทรัพยากรของหน้าหนึ่งๆ อย่างไร แม้จะมีชื่อ API แล้ว แต่ข้อมูลที่ API ให้นั้นไม่ได้จํากัดเพียงข้อมูลช่วงเวลา (แต่มีข้อมูลจำนวนมาก) ข้อมูลอื่นๆ ที่คุณเข้าถึงได้มีดังนี้
initiatorType
: วิธีที่ดึงทรัพยากร เช่น จากแท็ก<script>
หรือ<link>
หรือจากการเรียกใช้fetch()
nextHopProtocol
: โปรโตคอลที่ใช้ในการดึงทรัพยากร เช่นh2
หรือquic
encodedBodySize
/decodedBodySize]: ขนาดของทรัพยากรในรูปแบบที่เข้ารหัสหรือถอดรหัส (ตามลำดับ)transferSize
: ขนาดของทรัพยากรที่โอนผ่านเครือข่ายจริง เมื่อแคชใช้ทรัพยากรแล้ว ค่านี้อาจน้อยกว่าencodedBodySize
มาก และในบางกรณีอาจเป็น 0 ได้ (หากไม่มีการตรวจสอบแคชอีกครั้ง)
คุณสามารถใช้พร็อพเพอร์ตี้ transferSize
ของรายการเวลาของทรัพยากรเพื่อวัดเมตริกอัตรา Hit ของแคชหรือเมตริกขนาดทรัพยากรที่แคชไว้ทั้งหมด ซึ่งอาจเป็นประโยชน์ในการทำความเข้าใจว่ากลยุทธ์การแคชทรัพยากรมีผลต่อประสิทธิภาพสำหรับผู้เข้าชมซ้ำอย่างไร
ตัวอย่างต่อไปนี้จะบันทึกทรัพยากรทั้งหมดที่หน้าเว็บขอ และระบุว่าทรัพยากรแต่ละรายการได้ดำเนินการโดยแคชหรือไม่
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// If transferSize is 0, the resource was fulfilled using the cache.
console.log(entry.name, entry.transferSize === 0);
}
});
// Start listening for `resource` entries to be dispatched.
po.observe({type: 'resource', buffered: true});
API การจับเวลาการนำทาง
Navigation Timing API คล้ายกับ Resource Timing API แต่จะรายงานเฉพาะคำขอการนำทางเท่านั้น ประเภทรายการ navigation
ยังคล้ายกับประเภทรายการ resource
เช่นกัน แต่จะมีข้อมูลเพิ่มเติมเฉพาะสำหรับคำขอการนำทางเท่านั้น (เช่น เมื่อเหตุการณ์ DOMContentLoaded
และ load
เริ่มทำงาน)
เมตริกหนึ่งที่นักพัฒนาซอฟต์แวร์จำนวนมากติดตามเพื่อทำความเข้าใจเวลาตอบสนองของเซิร์ฟเวอร์ (Time to First Byte (TTFB)) มีให้ใช้งานโดยใช้ Navigation Timing API หรือก็คือการประทับเวลา responseStart
ของรายการ
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// If transferSize is 0, the resource was fulfilled using the cache.
console.log('Time to first byte', entry.responseStart);
}
});
// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});
อีกเมตริกหนึ่งที่นักพัฒนาซอฟต์แวร์ที่ใช้ Service Worker อาจคำนึงถึงคือเวลาเริ่มต้นของ Service Worker สำหรับคำขอการนำทาง นี่คือระยะเวลาที่เบราว์เซอร์ใช้ในการเริ่มชุดข้อความของ Service Worker ก่อนที่จะเริ่มดักจับเหตุการณ์การดึงข้อมูล
เวลาเริ่มต้นของโปรแกรมทำงานของบริการสำหรับคำขอการนำทางหนึ่งๆ สามารถระบุได้จากเดลต้าระหว่าง entry.responseStart
ถึง entry.workerStart
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log('Service Worker startup time:',
entry.responseStart - entry.workerStart);
}
});
// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});
API ระยะเวลาของเซิร์ฟเวอร์
Server Timing API ช่วยให้คุณส่งข้อมูลเวลาที่เจาะจงของคำขอจากเซิร์ฟเวอร์ไปยังเบราว์เซอร์ผ่านส่วนหัวการตอบกลับได้ เช่น คุณระบุระยะเวลาที่ใช้ในการค้นหาข้อมูลในฐานข้อมูลสำหรับคำขอหนึ่งๆ ได้ ซึ่งจะเป็นประโยชน์ในการแก้ไขข้อบกพร่องด้านประสิทธิภาพเนื่องจากเซิร์ฟเวอร์ทำงานช้า
สำหรับนักพัฒนาซอฟต์แวร์ที่ใช้ผู้ให้บริการวิเคราะห์บุคคลที่สาม Server Timing API เป็นวิธีเดียวในการเชื่อมโยงข้อมูลประสิทธิภาพของเซิร์ฟเวอร์กับเมตริกทางธุรกิจอื่นๆ ที่เครื่องมือวิเคราะห์เหล่านี้อาจกำลังวัดผลอยู่
หากต้องการระบุข้อมูลเวลาของเซิร์ฟเวอร์ในการตอบสนอง คุณสามารถใช้ส่วนหัวการตอบกลับ Server-Timing
ได้ ตัวอย่างมีดังนี้
HTTP/1.1 200 OK
Server-Timing: miss, db;dur=53, app;dur=47.2
จากนั้น คุณจะอ่านข้อมูลนี้ได้ทั้งในหน้าเว็บ resource
หรือ navigation
จาก Resource Timing และ Navigation Timing API
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Logs all server timing data for this response
console.log('Server Timing', entry.serverTiming);
}
});
// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});