การวัดการโต้ตอบกับ Next Paint (INP)

1. บทนำ

นี่คือ Codelab แบบอินเทอร์แอกทีฟสำหรับการเรียนรู้วิธีวัด Interaction to Next Paint (INP) โดยใช้ไลบรารี web-vitals

ข้อกำหนดเบื้องต้น

สิ่งที่คุณจะได้เรียนรู้

  • วิธีเพิ่มไลบรารี web-vitals ลงในหน้าเว็บและใช้ข้อมูลการระบุแหล่งที่มา
  • ใช้ข้อมูลการระบุแหล่งที่มาเพื่อวินิจฉัยว่าควรเริ่มปรับปรุง INP ที่ใดและอย่างไร

สิ่งที่คุณต้องมี

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

2. ตั้งค่า

รับและเรียกใช้โค้ด

โค้ดนี้อยู่ในที่เก็บweb-vitals-codelabs

  1. โคลนที่เก็บในเทอร์มินัล: git clone https://github.com/GoogleChromeLabs/web-vitals-codelabs.git
  2. ไปยังไดเรกทอรีที่โคลน: cd web-vitals-codelabs/measuring-inp
  3. ติดตั้งทรัพยากร Dependency: npm ci
  4. เริ่มเว็บเซิร์ฟเวอร์: npm run start
  5. ไปที่ http://localhost:8080/ ในเบราว์เซอร์

ลองใช้หน้าเว็บ

Codelab นี้ใช้ Gastropodicon (เว็บไซต์อ้างอิงกายวิภาคของหอยทากยอดนิยม) เพื่อสำรวจปัญหาที่อาจเกิดขึ้นกับ INP

ภาพหน้าจอของหน้าเดโม Gastropodicon

ลองโต้ตอบกับหน้าเว็บเพื่อดูว่าการโต้ตอบใดช้า

3. การเริ่มต้นใช้งานเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome

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

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

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

ภาพหน้าจอของแผงประสิทธิภาพ DevTools ข้างแอป โดยเลือกการชะลอ CPU 4 เท่า

4. การติดตั้ง web-vitals

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

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

Codelab นี้จะติดตั้งจาก npm และโหลดสคริปต์โดยตรงเพื่อหลีกเลี่ยงการเจาะลึกกระบวนการบิลด์ที่เฉพาะเจาะจง

web-vitals มี 2 เวอร์ชันที่คุณใช้ได้ ดังนี้

  • ควรใช้บิลด์ "มาตรฐาน" หากต้องการติดตามค่าเมตริกของ Core Web Vitals เมื่อโหลดหน้าเว็บ
  • การสร้าง "การระบุแหล่งที่มา" จะเพิ่มข้อมูลการแก้ไขข้อบกพร่องเพิ่มเติมลงในเมตริกแต่ละรายการเพื่อวินิจฉัยว่าเหตุใดเมตริกจึงมีค่าตามที่แสดง

เราต้องการให้มีการสร้างการระบุแหล่งที่มาเพื่อวัด INP ใน Codelab นี้

เพิ่ม web-vitals ลงใน devDependencies ของโปรเจ็กต์โดยเรียกใช้ npm install -D web-vitals

วิธีเพิ่ม web-vitals ลงในหน้าเว็บ

เพิ่มสคริปต์เวอร์ชันการระบุแหล่งที่มาที่ด้านล่างของ index.html และบันทึกผลลัพธ์ลงในคอนโซล

<script type="module">
  import {onINP} from './node_modules/web-vitals/dist/web-vitals.attribution.js';

  onINP(console.log);
</script>

ลองเลย

ลองโต้ตอบกับหน้าเว็บอีกครั้งโดยเปิดคอนโซลไว้ เมื่อคุณคลิกไปรอบๆ หน้าเว็บ ระบบจะไม่บันทึกอะไรเลย

INP จะวัดตลอดวงจรทั้งหมดของหน้าเว็บ ดังนั้นโดยค่าเริ่มต้น web-vitals จะไม่รายงาน INP จนกว่าผู้ใช้จะออกจากหรือปิดหน้าเว็บ ลักษณะการทำงานนี้เหมาะสำหรับการส่งสัญญาณเพื่อการวิเคราะห์ แต่ไม่เหมาะสำหรับการแก้ไขข้อบกพร่องแบบอินเทอร์แอกทีฟ

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

ลองเพิ่มตัวเลือกไปยังสคริปต์และโต้ตอบกับหน้าเว็บอีกครั้ง

<script type="module">
  import {onINP} from './node_modules/web-vitals/dist/web-vitals.attribution.js';

  onINP(console.log, {reportAllChanges: true});
</script>

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

ภาพหน้าจอของคอนโซล DevTools ที่พิมพ์ข้อความ INP ลงในคอนโซลเรียบร้อยแล้ว

5. การระบุแหล่งที่มาประกอบด้วยอะไรบ้าง

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

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

คลิกใช่เพื่อยอมรับคุกกี้ (สาธิต) และดูข้อมูล INP ที่บันทึกไว้ในคอนโซล DevTools

ออบเจ็กต์ข้อมูล INP ที่บันทึกลงในคอนโซลเครื่องมือสำหรับนักพัฒนาเว็บ

ข้อมูลระดับบนสุดนี้พร้อมใช้งานทั้งใน Web Vitals มาตรฐานและ Web Vitals การระบุแหล่งที่มา

{
  name: 'INP',
  value: 344,
  rating: 'needs-improvement',
  entries: [...],
  id: 'v4-1715732159298-8028729544485',
  navigationType: 'reload',
  attribution: {...},
}

ระยะเวลาตั้งแต่ผู้ใช้คลิกจนถึงการแสดงผลครั้งถัดไปคือ 344 มิลลิวินาที ซึ่งเป็น INP ที่"ต้องปรับปรุง" entries อาร์เรย์มีค่า PerformanceEntry ทั้งหมดที่เชื่อมโยงกับการโต้ตอบนี้ ในกรณีนี้คือเหตุการณ์คลิกเพียงรายการเดียว

แต่เราสนใจพร็อพเพอร์ตี้ attribution มากที่สุดเพื่อดูว่าเกิดอะไรขึ้นในช่วงเวลานี้ ในการสร้างข้อมูลการระบุแหล่งที่มา web-vitals จะค้นหา Long Animations Frame (LoAF) ที่ทับซ้อนกับเหตุการณ์คลิก จากนั้น LoAF จะให้ข้อมูลโดยละเอียดเกี่ยวกับระยะเวลาที่ใช้ในเฟรมนั้น ตั้งแต่สคริปต์ที่ทำงานไปจนถึงเวลาที่ใช้ในrequestAnimationFrame Callback, สไตล์ และเลย์เอาต์

ขยายพร็อพเพอร์ตี้ attribution เพื่อดูข้อมูลเพิ่มเติม ข้อมูลมีความสมบูรณ์มากขึ้น

attribution: {
  interactionTargetElement: Element,
  interactionTarget: '#confirm',
  interactionType: 'pointer',

  inputDelay: 27,
  processingDuration: 295.6,
  presentationDelay: 21.4,

  processedEventEntries: [...],
  longAnimationFrameEntries: [...],
}

ก่อนอื่น คุณจะเห็นข้อมูลเกี่ยวกับสิ่งที่โต้ตอบด้วย

  • interactionTargetElement: การอ้างอิงแบบเรียลไทม์ไปยังองค์ประกอบที่มีการโต้ตอบ (หากไม่ได้นำองค์ประกอบออกจาก DOM)
  • interactionTarget: ตัวเลือกสำหรับค้นหาองค์ประกอบภายในหน้าเว็บ

จากนั้น เราจะแบ่งช่วงเวลาออกเป็นระดับสูงดังนี้

  • inputDelay: เวลาตั้งแต่ที่ผู้ใช้เริ่มโต้ตอบ (เช่น คลิกเมาส์) จนถึงเวลาที่ Listener เหตุการณ์สำหรับการโต้ตอบนั้นเริ่มทํางาน ในกรณีนี้ ความล่าช้าของอินพุตอยู่ที่ประมาณ 27 มิลลิวินาทีเท่านั้น แม้ว่าจะเปิดการควบคุมปริมาณ CPU ไว้ก็ตาม
  • processingDuration: ระยะเวลาที่ Listener เหตุการณ์ใช้ในการทำงานจนเสร็จสมบูรณ์ โดยปกติแล้ว หน้าเว็บจะมี Listener หลายรายการสําหรับเหตุการณ์เดียว (เช่น pointerdown, pointerup และ click) หาก Listener ทั้งหมดทํางานในเฟรมภาพเคลื่อนไหวเดียวกัน ระบบจะรวม Listener เหล่านี้ไว้ในเวลานี้ ในกรณีนี้ ระยะเวลาการประมวลผลจะใช้เวลา 295.6 มิลลิวินาที ซึ่งเป็นระยะเวลา INP ส่วนใหญ่
  • presentationDelay: เวลาตั้งแต่ Listener เหตุการณ์ทํางานเสร็จจนถึงเวลาที่เบราว์เซอร์แสดงผลเฟรมถัดไปเสร็จ ในกรณีนี้คือ 21.4 มิลลิวินาที

ระยะ INP เหล่านี้อาจเป็นสัญญาณสำคัญในการวินิจฉัยสิ่งที่ต้องเพิ่มประสิทธิภาพ คู่มือการเพิ่มประสิทธิภาพ INP มีข้อมูลเพิ่มเติมในหัวข้อนี้

เมื่อเจาะลึกลงไปอีกเล็กน้อย processedEventEntries จะมีเหตุการณ์5 รายการ ซึ่งต่างจากอาร์เรย์ INP ระดับบนสุด entries ที่มีเหตุการณ์เดียว แตกต่างกันอย่างไร

processedEventEntries: [
  {
    name: 'mouseover',
    entryType: 'event',
    startTime: 1801.6,
    duration: 344,
    processingStart: 1825.3,
    processingEnd: 1825.3,
    cancelable: true
  },
  {
    name: 'mousedown',
    entryType: 'event',
    startTime: 1801.6,
    duration: 344,
    processingStart: 1825.3,
    processingEnd: 1825.3,
    cancelable: true
  },
  {name: 'mousedown', ...},
  {name: 'mouseup', ...},
  {name: 'click', ...},
],

รายการระดับบนสุดคือเหตุการณ์ INP ในกรณีนี้คือการคลิก การระบุแหล่งที่มา processedEventEntries คือเหตุการณ์ทั้งหมดที่ประมวลผลในเฟรมเดียวกัน โปรดสังเกตว่ามีเหตุการณ์อื่นๆ เช่น mouseover และ mousedown รวมอยู่ด้วย ไม่ใช่แค่เหตุการณ์คลิก การทราบเกี่ยวกับเหตุการณ์อื่นๆ เหล่านี้อาจมีความสำคัญอย่างยิ่งหากเหตุการณ์เหล่านั้นทำงานช้าด้วย เนื่องจากเหตุการณ์ทั้งหมดมีส่วนทำให้การตอบสนองช้า

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

longAnimationFrameEntries

การขยายรายการ LoAF

longAnimationFrameEntries: [{
  name: 'long-animation-frame',
  startTime: 1823,
  duration: 319,

  renderStart: 2139.5,
  styleAndLayoutStart: 2139.7,
  firstUIEventTimestamp: 1801.6,
  blockingDuration: 268,

  scripts: [{...}]
}],

ซึ่งมีค่าที่มีประโยชน์มากมาย เช่น การแบ่งเวลาที่ใช้ในการจัดรูปแบบ บทความเกี่ยวกับ Long Animation Frames API จะอธิบายพร็อพเพอร์ตี้เหล่านี้อย่างละเอียด ตอนนี้เราสนใจscriptsพร็อพเพอร์ตี้เป็นหลัก ซึ่งมีรายการที่ให้รายละเอียดเกี่ยวกับสคริปต์ที่รับผิดชอบเฟรมที่ทำงานนาน

scripts: [{
  name: 'script',
  invoker: 'BUTTON#confirm.onclick',
  invokerType: 'event-listener',

  startTime: 1828.6,
  executionStart: 1828.6,
  duration: 294,

  sourceURL: 'http://localhost:8080/third-party/cmp.js',
  sourceFunctionName: '',
  sourceCharPosition: 1144
}]

ในกรณีนี้ เราจะบอกได้ว่าเวลาส่วนใหญ่ใช้ไปกับevent-listenerเดียว ซึ่งเรียกใช้ใน BUTTON#confirm.onclick เรายังดู URL ของแหล่งที่มาของสคริปต์และตำแหน่งอักขระที่กำหนดฟังก์ชันได้ด้วย

สิ่งที่ได้เรียนรู้

เราจะพิจารณากรณีนี้จากข้อมูลการระบุแหล่งที่มานี้ได้อย่างไร

  • การโต้ตอบเกิดขึ้นจากการคลิกองค์ประกอบ button#confirm (จาก attribution.interactionTarget และพร็อพเพอร์ตี้ invoker ในรายการการระบุแหล่งที่มาของสคริปต์)
  • เวลาส่วนใหญ่ใช้ไปกับการเรียกใช้เครื่องมือฟังเหตุการณ์ (จาก attribution.processingDuration เทียบกับเมตริกทั้งหมด value)
  • โค้ด Listener เหตุการณ์ที่ทำงานช้าเริ่มต้นจาก Listener การคลิกที่กำหนดไว้ใน third-party/cmp.js (จาก scripts.sourceURL)

ซึ่งเป็นข้อมูลที่เพียงพอที่จะทราบว่าเราต้องเพิ่มประสิทธิภาพที่ใด

6. Listener เหตุการณ์หลายรายการ

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

เริ่มพิมพ์ในช่องค้นหา ข้อมูลการระบุแหล่งที่มาแสดงอะไร คุณคิดว่าเกิดอะไรขึ้น

ข้อมูลการระบุแหล่งที่มา

ก่อนอื่น เรามาดูภาพรวมของตัวอย่างการทดสอบเดโมกัน

{
  name: 'INP',
  value: 1072,
  rating: 'poor',
  attribution: {
    interactionTargetElement: Element,
    interactionTarget: '#search-terms',
    interactionType: 'keyboard',

    inputDelay: 3.3,
    processingDuration: 1060.6,
    presentationDelay: 8.1,

    processedEventEntries: [...],
    longAnimationFrameEntries: [...],
  }
}

เป็นค่า INP ที่ไม่ดี (เมื่อเปิดใช้การควบคุมปริมาณ CPU) จากการโต้ตอบด้วยแป้นพิมพ์กับองค์ประกอบ input#search-terms ส่วนใหญ่ใช้เวลา 1,061 มิลลิวินาทีจาก INP ทั้งหมด 1,072 มิลลิวินาทีในการประมวลผล

อย่างไรก็ตาม รายการ scripts น่าสนใจกว่า

การสลับเลย์เอาต์

รายการแรกของอาร์เรย์ scripts ให้บริบทที่มีประโยชน์แก่เราดังนี้

scripts: [{
  name: 'script',
  invoker: 'BUTTON#confirm.onclick',
  invokerType: 'event-listener',

  startTime: 4875.6,
  executionStart: 4875.6,
  duration: 497,
  forcedStyleAndLayoutDuration: 388,

  sourceURL: 'http://localhost:8080/js/index.js',
  sourceFunctionName: 'handleSearch',
  sourceCharPosition: 940
},
...]

ระยะเวลาในการประมวลผลส่วนใหญ่จะเกิดขึ้นระหว่างการเรียกใช้สคริปต์นี้ ซึ่งเป็นinput Listener (ผู้เรียกใช้คือ INPUT#search-terms.oninput) ระบบจะระบุชื่อฟังก์ชัน (handleSearch) รวมถึงตำแหน่งอักขระภายในไฟล์ต้นฉบับ index.js

แต่มีพร็อพเพอร์ตี้ใหม่คือ forcedStyleAndLayoutDuration นี่คือเวลาที่ใช้ในการเรียกใช้สคริปต์นี้ซึ่งเบราว์เซอร์ถูกบังคับให้จัดเลย์เอาต์หน้าเว็บใหม่ กล่าวคือ 78% ของเวลาทั้งหมด (388 มิลลิวินาทีจาก 497) ที่ใช้ในการเรียกใช้เครื่องมือฟังเหตุการณ์นี้จริงๆ แล้วใช้ไปกับการสลับเลย์เอาต์

เราควรให้ความสำคัญกับการแก้ไขปัญหานี้เป็นอันดับแรก

ผู้ฟังที่ฟังซ้ำ

โดยแต่ละรายการใน 2 รายการสคริปต์ถัดไปไม่ได้มีอะไรที่โดดเด่นเป็นพิเศษ

scripts: [...,
{
  name: 'script',
  invoker: '#document.onkeyup',
  invokerType: 'event-listener',

  startTime: 5375.3,
  executionStart: 5375.3,
  duration: 124,

  sourceURL: 'http://localhost:8080/js/index.js',
  sourceFunctionName: '',
  sourceCharPosition: 1526,
},
{
  name: 'script',
  invoker: '#document.onkeyup',
  invokerType: 'event-listener',

  startTime: 5673.9,
  executionStart: 5673.9,
  duration: 95,

  sourceURL: 'http://localhost:8080/js/index.js',
  sourceFunctionName: '',
  sourceCharPosition: 1526
}]

ทั้ง 2 รายการเป็นkeyup Listener ที่จะทำงานต่อกัน Listener เป็นฟังก์ชันที่ไม่ระบุชื่อ (จึงไม่มีการรายงานอะไรในพร็อพเพอร์ตี้ sourceFunctionName) แต่เรายังมีไฟล์ต้นฉบับและตำแหน่งอักขระ จึงค้นหาตำแหน่งของโค้ดได้

สิ่งที่แปลกคือทั้ง 2 รายการมาจากไฟล์แหล่งที่มาและตำแหน่งอักขระเดียวกัน

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

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

เนื่องจากเป็นการโต้ตอบการค้นหา/การเติมข้อความอัตโนมัติ กลยุทธ์ที่ดีคือการลดการกระเด้งของอินพุต เพื่อให้ระบบประมวลผลการกดแป้นพิมพ์อย่างมากที่สุด 1 ครั้งต่อเฟรม

7. ความล่าช้าของอินพุต

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

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

หน้าเดโมมีฟีเจอร์ลับที่หากคุณคลิกโลโก้หอยทากที่ด้านบนของหน้า ระบบจะเริ่มเคลื่อนไหวและทำงาน JavaScript ในเทรดหลักอย่างหนัก

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

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

ในหลายๆ หน้า งานในเทรดหลักที่มีการทำงานหนักอาจไม่เป็นเช่นนี้ แต่ก็เป็นตัวอย่างที่ดีที่แสดงให้เห็นว่าสามารถระบุได้ในข้อมูลการระบุแหล่งที่มาของ INP

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

{
  name: 'INP',
  value: 728,
  rating: 'poor',

  attribution: {
    interactionTargetElement: Element,
    interactionTarget: '#search-terms',
    interactionType: 'pointer',

    inputDelay: 702.3,
    processingDuration: 4.9,
    presentationDelay: 20.8,

    longAnimationFrameEntries: [{
      name: 'long-animation-frame',
      startTime: 2064.8,
      duration: 790,

      renderStart: 2065,
      styleAndLayoutStart: 2854.2,
      firstUIEventTimestamp: 0,
      blockingDuration: 740,

      scripts: [{...}]
    }]
  }
}

ตามที่คาดไว้ ตัวแฮนเดิลเหตุการณ์ทํางานอย่างรวดเร็ว โดยแสดงระยะเวลาการประมวลผล 4.9 มิลลิวินาที และการโต้ตอบที่ไม่ดีส่วนใหญ่ใช้เวลาในการหน่วงเวลาอินพุต ซึ่งใช้เวลา 702.3 มิลลิวินาทีจากทั้งหมด 728 มิลลิวินาที

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

รายการสคริปต์ LoAF จะช่วยคุณได้

scripts: [{
  name: 'script',
  invoker: 'SPAN.onanimationiteration',
  invokerType: 'event-listener',

  startTime: 2065,
  executionStart: 2065,
  duration: 788,

  sourceURL: 'http://localhost:8080/js/index.js',
  sourceFunctionName: 'cryptodaphneCoinHandler',
  sourceCharPosition: 1831
}]

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

จากข้อมูลนี้ เราจะเห็นว่าฟังก์ชันที่ทำให้การประมวลผลการโต้ตอบล่าช้าถูกทริกเกอร์ได้อย่างไร (โดยanimationiteration Listener) ฟังก์ชันใดที่รับผิดชอบ และฟังก์ชันนั้นอยู่ที่ใดในไฟล์แหล่งที่มา

8. การนำเสนอช้า: เมื่อการอัปเดตไม่แสดง

ความล่าช้าในการนำเสนอจะวัดเวลาตั้งแต่เมื่อตัวแฮนเดิลเหตุการณ์ทํางานเสร็จจนกว่าเบราว์เซอร์จะวาดเฟรมใหม่ลงในหน้าจอได้ ซึ่งจะแสดงความคิดเห็นที่ผู้ใช้มองเห็น

รีเฟรชหน้าเว็บเพื่อรีเซ็ตค่า INP อีกครั้ง แล้วเปิดเมนูแฮมเบอร์เกอร์ มีปัญหาแน่นอนเมื่อเปิด

การดำเนินการนี้มีลักษณะอย่างไร

{
  name: 'INP',
  value: 376,
  rating: 'needs-improvement',
  delta: 352,

  attribution: {
    interactionTarget: '#sidenav-button>svg',
    interactionType: 'pointer',

    inputDelay: 12.8,
    processingDuration: 14.7,
    presentationDelay: 348.5,

    longAnimationFrameEntries: [{
      name: 'long-animation-frame',
      startTime: 651,
      duration: 365,

      renderStart: 673.2,
      styleAndLayoutStart: 1004.3,
      firstUIEventTimestamp: 138.6,
      blockingDuration: 315,

      scripts: [{...}]
    }]
  }
}

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

scripts: [{
  entryType: 'script',
  invoker: 'FrameRequestCallback',
  invokerType: 'user-callback',

  startTime: 673.8,
  executionStart: 673.8,
  duration: 330,

  sourceURL: 'http://localhost:8080/js/side-nav.js',
  sourceFunctionName: '',
  sourceCharPosition: 1193,
}]

เมื่อดูรายการเดียวในอาร์เรย์ scripts เราจะเห็นว่าเวลาที่ใช้ใน user-callback มาจาก FrameRequestCallback ครั้งนี้ความล่าช้าในการนำเสนอเกิดจากการเรียกกลับของ requestAnimationFrame

9. บทสรุป

การรวบรวมข้อมูลฟิลด์

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

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

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

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

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

การระบุแหล่งที่มาทุกที่

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

ตอนนี้คุณพร้อมที่จะใช้ข้อมูลการระบุแหล่งที่มาของ INP ในเว็บไซต์แล้ว

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

const script = document.createElement('script');
script.src = 'https://unpkg.com/web-vitals@4/dist/web-vitals.attribution.iife.js';
script.onload = function () {
  webVitals.onINP(console.log, {reportAllChanges: true});
};
document.head.appendChild(script);

ดูข้อมูลเพิ่มเติม