เมตริกที่กำหนดเอง

การมีเมตริกที่เน้นผู้ใช้เป็นศูนย์กลางนั้นมีประโยชน์มากมาย ซึ่งคุณสามารถวัดค่าต่างๆ ได้ในทุกเว็บไซต์ เมตริกเหล่านี้ช่วยให้คุณทำสิ่งต่อไปนี้ได้

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

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

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

  • ระยะเวลาที่ใช้ในการเปลี่ยนแอปแบบหน้าเดียว (SPA) จาก "หน้าเว็บ" หนึ่งไปยังอีก "หน้า" หนึ่ง
  • เวลาที่หน้าเว็บใช้ในการแสดงข้อมูลที่ดึงมาจากฐานข้อมูลสำหรับผู้ใช้ที่เข้าสู่ระบบ
  • ระยะเวลาที่แอปที่แสดงผลฝั่งเซิร์ฟเวอร์ (SSR) ใช้ในการเพิ่มปริมาณ
  • อัตราการพบแคชสำหรับทรัพยากรที่โหลดโดยผู้เข้าชมที่กลับมา
  • เวลาในการตอบสนองของเหตุการณ์ของเหตุการณ์การคลิกหรือแป้นพิมพ์ในเกม

API สำหรับวัดเมตริกที่กำหนดเอง

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

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

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

API เครื่องมือสังเกตประสิทธิภาพ

การรองรับเบราว์เซอร์

  • 52
  • 79
  • 57
  • 11

แหล่งที่มา

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

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

หากต้องการสร้าง PerformanceObserver ให้ส่งผ่าน Callback เพื่อเรียกใช้ทุกครั้งที่มีการส่งรายการด้านประสิทธิภาพใหม่ จากนั้นให้บอกผู้สังเกตการณ์ว่าจะฟังรายการประเภทใดโดยใช้เมธอด observe() ดังนี้

// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  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'});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

ส่วนต่อไปนี้จะแสดงรายการประเภทต่างๆ ทั้งหมดที่ดูได้ แต่จะตรวจสอบประเภทรายการที่ใช้ได้ผ่านพร็อพเพอร์ตี้ 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 ใหม่จำนวนมาก (เช่น งานแบบยาว) จะไม่แสดงผ่านออบเจ็กต์ performance แต่จะแสดงผ่าน PerformanceObserver เท่านั้น

คุณควรหลีกเลี่ยงวิธีการเหล่านี้ในโค้ดและใช้ PerformanceObserver นับจากนี้เป็นต้นไป ยกเว้นกรณีที่คุณต้องการความเข้ากันได้กับ Internet Explorer

API ระยะเวลาของผู้ใช้

User Timing API เป็น 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 ดังนี้

// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

API ของงานที่ใช้เวลานาน

การรองรับเบราว์เซอร์

  • 58
  • 79
  • x
  • x

แหล่งที่มา

Long Tasks API มีประโยชน์ในการช่วยให้ทราบเมื่อเทรดหลักของเบราว์เซอร์ถูกบล็อกเป็นเวลานานพอที่จะส่งผลต่ออัตราเฟรมหรือเวลาในการตอบสนองของอินพุต API จะรายงานงานที่ดำเนินการนานกว่า 50 มิลลิวินาที

เมื่อใดก็ตามที่คุณต้องเรียกใช้โค้ดราคาแพง หรือโหลดและเรียกใช้สคริปต์ขนาดใหญ่ การติดตามว่าโค้ดดังกล่าวจะบล็อกเทรดหลักหรือไม่ อันที่จริงแล้ว มีเมตริกระดับสูงจำนวนมากสร้างขึ้นจาก Long Tasks API (เช่น Time to Interactive (TTI) และ Total Blocking Time (TBT))

ในการพิจารณาว่าจะมีงานที่ใช้เวลานานเกิดขึ้นเมื่อใด คุณสามารถใช้ PerformanceObserver และลงทะเบียนเพื่อติดตามรายการประเภท longtask ดังต่อไปนี้

// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

Element Timing API

การรองรับเบราว์เซอร์

  • 77
  • 79
  • x
  • x

แหล่งที่มา

เมตริก Largest Contentful Paint (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>
  // Catch errors since some browsers throw when using the new `type` option.
  // https://bugs.webkit.org/show_bug.cgi?id=209216
  try {
    // Create the performance observer.
    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});
  } catch (e) {
    // Do nothing if the browser doesn't support this API.
  }
</script>

API ระยะเวลาเหตุการณ์

เมตริก Interaction to Next Paint (INP) จะประเมินการตอบสนองของหน้าเว็บโดยรวมโดยสังเกตการโต้ตอบกับการคลิก การแตะ และแป้นพิมพ์ทั้งหมดตลอดอายุของหน้าเว็บ INP ของหน้าเว็บมักเป็นการโต้ตอบที่ใช้เวลาดำเนินการนานที่สุด นับตั้งแต่เวลาที่ผู้ใช้เริ่มการโต้ตอบ ไปจนถึงตอนที่เบราว์เซอร์วาดเฟรมถัดไปซึ่งแสดงผลอินพุตของผู้ใช้แบบเป็นภาพ

เมตริก INP สร้างขึ้นโดย Event Timing API API นี้จะแสดงการประทับเวลาจำนวนหนึ่งที่เกิดขึ้นระหว่างวงจรของเหตุการณ์ ซึ่งรวมถึงเหตุการณ์ต่อไปนี้

  • startTime: เวลาที่เบราว์เซอร์ได้รับเหตุการณ์
  • processingStart: เวลาที่เบราว์เซอร์เริ่มประมวลผลเครื่องจัดการเหตุการณ์ของเหตุการณ์นั้นได้
  • processingEnd: เวลาที่เบราว์เซอร์ดำเนินการโค้ดแบบซิงโครนัสทั้งหมดที่เริ่มต้นจากเครื่องจัดการเหตุการณ์สำหรับเหตุการณ์นี้เสร็จสิ้น
  • duration: เวลา (ปัดเศษเป็น 8 มิลลิวินาทีเพื่อความปลอดภัย) ระหว่างที่เบราว์เซอร์ได้รับเหตุการณ์จนกระทั่งสามารถวาดเฟรมถัดไปหลังจากรันโค้ดแบบซิงโครนัสทั้งหมดที่เริ่มต้นจากเครื่องจัดการเหตุการณ์เสร็จแล้ว

ตัวอย่างต่อไปนี้แสดงวิธีใช้ค่าเหล่านี้เพื่อสร้างการวัดที่กําหนดเอง

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  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 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 time (ms): ${processingTime}`);
      console.log(`Total event duration (ms): ${duration}`);
      console.log(`Event type: ${eventType}`);
      console.log(target);
    });
  });

  // A durationThreshold of 16ms is necessary to surface more
  // interactions, since the default is 104ms. The minimum
  // durationThreshold is 16ms.
  po.observe({type: 'event', buffered: true, durationThreshold: 16});
} catch (error) {
  // Do nothing if the browser doesn't support this API.
}

API การจับเวลาของทรัพยากร

Resource Timing API ทำให้นักพัฒนาแอปมีข้อมูลเชิงลึกโดยละเอียดว่ามีการโหลดทรัพยากรของหน้าหนึ่งๆ อย่างไร แม้จะมีชื่อ API แล้ว แต่ข้อมูลที่ API ให้นั้นไม่ได้จํากัดเพียงข้อมูลช่วงเวลา (แต่มีข้อมูลจำนวนมาก) ข้อมูลอื่นๆ ที่คุณเข้าถึงได้มีดังนี้

  • initiatorType: วิธีที่ดึงทรัพยากร เช่น จากแท็ก <script> หรือ <link> หรือจากการเรียกใช้ fetch()
  • nextHopProtocol: โปรโตคอลที่ใช้ในการดึงทรัพยากร เช่น h2 หรือ quic
  • encodedBodySize/decodedBodySize]: ขนาดของทรัพยากรในรูปแบบที่เข้ารหัสหรือถอดรหัส (ตามลำดับ)
  • transferSize: ขนาดของทรัพยากรที่โอนผ่านเครือข่ายจริง เมื่อแคชใช้ทรัพยากรแล้ว ค่านี้อาจน้อยกว่า encodedBodySize มาก และในบางกรณีอาจเป็น 0 ได้ (หากไม่มีการตรวจสอบแคชอีกครั้ง)

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

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

// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // If transferSize is 0, the resource was fulfilled via the cache.
      console.log(entry.name, entry.transferSize === 0);
    }
  });

  // Start listening for `resource` entries to be dispatched.
  po.observe({type: 'resource', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

การรองรับเบราว์เซอร์

  • 57
  • 12
  • 58
  • 15

แหล่งที่มา

navigation Timing API คล้ายกับ Resource Timing API แต่จะรายงานเฉพาะคำขอการนำทาง ประเภทรายการ navigation ยังคล้ายกับประเภทรายการ resource เช่นกัน แต่จะมีข้อมูลเพิ่มเติมเฉพาะสำหรับคำขอการนำทางเท่านั้น (เช่น เมื่อเหตุการณ์ DOMContentLoaded และ load เริ่มทำงาน)

เมตริกหนึ่งที่นักพัฒนาซอฟต์แวร์จำนวนมากติดตามเพื่อทำความเข้าใจเวลาตอบสนองของเซิร์ฟเวอร์ (Time to First Byte (TTFB)) มีให้ใช้งานโดยใช้ Navigation Timing API หรือก็คือการประทับเวลา responseStart ของรายการ

// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // If transferSize is 0, the resource was fulfilled via the cache.
      console.log('Time to first byte', entry.responseStart);
    }
  });

  // Start listening for `navigation` entries to be dispatched.
  po.observe({type: 'navigation', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

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

เวลาเริ่มต้นของโปรแกรมทำงานของบริการสำหรับคำขอการนำทางที่เจาะจงระบุได้จากเดลต้าระหว่าง entry.responseStart ถึง entry.workerStart

// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

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

// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}