تعاملات آهسته را در میدان پیدا کنید

یاد بگیرید که چگونه تعاملات کند را در داده‌های میدانی وب‌سایت خود پیدا کنید تا بتوانید فرصت‌هایی برای بهبود تعامل آن با Next Paint پیدا کنید.

داده‌های میدانی، داده‌هایی هستند که به شما می‌گویند کاربران واقعی چگونه وب‌سایت شما را تجربه می‌کنند. این داده‌ها مشکلاتی را که نمی‌توانید تنها در داده‌های آزمایشگاهی پیدا کنید، آشکار می‌کنند. در مورد تعامل تا رنگ بعدی (INP) ، داده‌های میدانی در شناسایی تعاملات کند ضروری هستند و سرنخ‌های حیاتی برای کمک به شما در رفع آنها ارائه می‌دهند.

در این راهنما، یاد خواهید گرفت که چگونه به سرعت INP وب‌سایت خود را با استفاده از داده‌های میدانی از گزارش تجربه کاربری کروم (CrUX) ارزیابی کنید تا ببینید آیا وب‌سایت شما با INP مشکلی دارد یا خیر. متعاقباً، یاد خواهید گرفت که چگونه از ساختار attribution کتابخانه جاوا اسکریپت web-vitals - و بینش‌های جدیدی که از API فریم‌های انیمیشن طولانی (LoAF) ارائه می‌دهد - برای جمع‌آوری و تفسیر داده‌های میدانی برای تعاملات کند در وب‌سایت خود استفاده کنید.

برای ارزیابی INP وب‌سایت خود، با CrUX شروع کنید.

اگر داده‌های میدانی را از کاربران وب‌سایت خود جمع‌آوری نمی‌کنید، CrUX می‌تواند نقطه شروع خوبی باشد. CrUX داده‌های میدانی را از کاربران واقعی کروم که ارسال داده‌های تله‌متری را انتخاب کرده‌اند، جمع‌آوری می‌کند.

داده‌های CrUX در حوزه‌های مختلفی ارائه می‌شوند و بستگی به دامنه اطلاعاتی دارد که به دنبال آن هستید. CrUX می‌تواند داده‌هایی در مورد INP و سایر Core Web Vitals برای موارد زیر ارائه دهد:

  • صفحات جداگانه و کل ریشه‌ها با استفاده از PageSpeed ​​Insights .
  • انواع صفحات. به عنوان مثال، بسیاری از وب‌سایت‌های تجارت الکترونیک دارای انواع صفحه جزئیات محصول و صفحه فهرست محصولات هستند. می‌توانید داده‌های CrUX را برای انواع صفحات منحصر به فرد در کنسول جستجو دریافت کنید.

به عنوان نقطه شروع، می‌توانید آدرس اینترنتی وب‌سایت خود را در PageSpeed ​​Insights وارد کنید. پس از وارد کردن آدرس اینترنتی، داده‌های فیلد مربوط به آن - در صورت وجود - برای معیارهای مختلف، از جمله INP نمایش داده می‌شوند. همچنین می‌توانید از دکمه‌های تغییر وضعیت برای بررسی مقادیر INP خود برای ابعاد موبایل و دسکتاپ استفاده کنید.

داده‌های میدانی همانطور که توسط CrUX در PageSpeed ​​Insights نشان داده شده است، LCP، INP، CLS را در سه Core Web Vitals و TTFB، FCP را به عنوان معیارهای تشخیصی و FID را به عنوان یک معیار منسوخ شده Core Web Vital نشان می‌دهد.
بازخوانی داده‌های CrUX همانطور که در PageSpeed ​​Insights مشاهده می‌شود. در این مثال، INP صفحه وب مورد نظر نیاز به بهبود دارد.

این داده‌ها مفید هستند زیرا به شما می‌گویند که آیا مشکلی دارید یا خیر. با این حال، کاری که CrUX نمی‌تواند انجام دهد این است که به شما بگوید چه چیزی باعث ایجاد مشکل می‌شود. راه‌حل‌های نظارت بر کاربر واقعی (RUM) زیادی وجود دارد که به شما کمک می‌کند داده‌های میدانی خود را از کاربران وب‌سایت خود جمع‌آوری کنید تا به شما در پاسخ به آن کمک کند، و یک گزینه این است که خودتان داده‌های میدانی را با استفاده از کتابخانه جاوا اسکریپت web-vitals جمع‌آوری کنید.

جمع‌آوری داده‌های میدانی با کتابخانه جاوااسکریپت web-vitals

کتابخانه جاوا اسکریپت web-vitals اسکریپتی است که می‌توانید در وب‌سایت خود بارگذاری کنید تا داده‌های میدانی را از کاربران وب‌سایت خود جمع‌آوری کنید. می‌توانید از آن برای ثبت تعدادی از معیارها، از جمله INP در مرورگرهایی که از آن پشتیبانی می‌کنند، استفاده کنید.

Browser Support

  • کروم: ۹۶.
  • لبه: ۹۶.
  • فایرفاکس: ۱۴۴.
  • سافاری: پشتیبانی نمی‌شود.

Source

می‌توان از نسخه استاندارد کتابخانه web-vitals برای دریافت داده‌های اولیه INP از کاربران در این زمینه استفاده کرد:

import {onINP} from 'web-vitals';

onINP(({name, value, rating}) => {
  console.log(name);    // 'INP'
  console.log(value);   // 512
  console.log(rating);  // 'poor'
});

برای تجزیه و تحلیل داده‌های میدانی کاربران، باید این داده‌ها را به جایی ارسال کنید:

import {onINP} from 'web-vitals';

onINP(({name, value, rating}) => {
  // Prepare JSON to be sent for collection. Note that
  // you can add anything else you'd want to collect here:
  const body = JSON.stringify({name, value, rating});

  // Use `sendBeacon` to send data to an analytics endpoint.
  // For Google Analytics, see https://github.com/GoogleChrome/web-vitals#send-the-results-to-google-analytics.
  navigator.sendBeacon('/analytics', body);
});

با این حال، این داده‌ها به خودی خود اطلاعات بیشتری نسبت به CrUX به شما نمی‌دهند. اینجاست که ساختار Attribution کتابخانه web-vitals وارد عمل می‌شود.

با ساختار تخصیص کتابخانه‌ی web-vitals فراتر بروید

ساختار attribution کتابخانه web-vitals داده‌های اضافی را که می‌توانید از کاربران در این زمینه دریافت کنید، ارائه می‌دهد تا به شما در عیب‌یابی بهتر تعاملات مشکل‌ساز که بر INP وب‌سایت شما تأثیر می‌گذارند، کمک کند. این داده‌ها از طریق شیء attribution که در متد onINP() کتابخانه نمایش داده می‌شود، قابل دسترسی هستند:

import {onINP} from 'web-vitals/attribution';

onINP(({name, value, rating, attribution}) => {
  console.log(name);         // 'INP'
  console.log(value);        // 56
  console.log(rating);       // 'good'
  console.log(attribution);  // Attribution data object
});
نحوه نمایش لاگ‌های کنسول از کتابخانه web-vitals. کنسول در این مثال، نام معیار (INP)، مقدار INP (56)، محل قرارگیری آن مقدار در آستانه‌های INP (خوب) و بخش‌های مختلف اطلاعات نشان داده شده در شیء attribution، از جمله ورودی‌های API فریم‌های انیمیشن بلند، را نشان می‌دهد.
نحوه نمایش داده‌های کتابخانه web-vitals در کنسول.

علاوه بر خود INP صفحه، ساختار attribution داده‌های زیادی را در اختیار شما قرار می‌دهد که می‌توانید از آنها برای درک دلایل کندی تعاملات، از جمله اینکه روی کدام بخش از تعامل باید تمرکز کنید، استفاده کنید. این می‌تواند به شما در پاسخ به سؤالات مهمی مانند موارد زیر کمک کند:

  • آیا کاربر هنگام بارگذاری صفحه با آن تعامل داشت؟
  • «آیا گرداننده‌های رویدادِ تعامل برای مدت طولانی اجرا شدند؟»
  • «آیا کد کنترل‌کننده رویداد تعامل از شروع به تأخیر افتاد؟ اگر چنین است، در آن زمان چه اتفاق دیگری در نخ اصلی می‌افتاد؟»
  • «آیا این تعامل باعث شد کار رندرینگ زیادی انجام شود که باعث تأخیر در رنگ‌آمیزی فریم بعدی شود؟»

جدول زیر برخی از داده‌های اولیه‌ی انتساب را که می‌توانید از کتابخانه دریافت کنید، نشان می‌دهد که می‌تواند به شما در تشخیص برخی از دلایل سطح بالای کندی تعاملات در وب‌سایتتان کمک کند:

کلید شیء attribution داده‌ها
interactionTarget یک انتخابگر CSS که به عنصری که مقدار INP صفحه را تولید کرده است اشاره می‌کند - برای مثال، button#save .
interactionType نوع تعامل، چه از طریق کلیک، تپ یا ورودی‌های صفحه‌کلید.
inputDelay * تأخیر ورودی تعامل.
processingDuration * مدت زمانی که از زمانی که اولین شنونده رویداد در پاسخ به تعامل کاربر شروع به اجرا می‌کند تا زمانی که تمام پردازش‌های شنونده رویداد به پایان می‌رسد.
presentationDelay * تأخیر نمایش تعامل، که از زمان پایان کار کنترل‌کننده‌های رویداد تا زمان ترسیم فریم بعدی رخ می‌دهد.
longAnimationFrameEntries * ورودی‌های LoAF مرتبط با تعامل. برای اطلاعات بیشتر به بعدی مراجعه کنید.
*جدید در نسخه ۴

با شروع نسخه ۴ کتابخانه web-vitals، می‌توانید از طریق داده‌هایی که با تجزیه فاز INP (تأخیر ورودی، مدت زمان پردازش و تأخیر ارائه) و API فریم‌های انیمیشن طولانی (LoAF) ارائه می‌دهد، بینش عمیق‌تری نسبت به تعاملات مشکل‌ساز کسب کنید.

API فریم‌های انیمیشن بلند (LoAF)

Browser Support

  • کروم: ۱۲۳.
  • لبه: ۱۲۳.
  • فایرفاکس: پشتیبانی نمی‌شود.
  • سافاری: پشتیبانی نمی‌شود.

Source

اشکال‌زدایی تعاملات با استفاده از داده‌های میدانی یک کار چالش‌برانگیز است. با این حال، با داده‌های LoAF، اکنون می‌توان بینش بهتری در مورد علل کندی تعاملات به دست آورد، زیرا LoAF تعدادی از زمان‌بندی‌های دقیق و داده‌های دیگری را که می‌توانید برای مشخص کردن علل دقیق - و مهم‌تر از آن، محل منبع مشکل در کد وب‌سایت خود - استفاده کنید، در اختیار شما قرار می‌دهد.

ساختار attribution کتابخانه web-vitals آرایه‌ای از ورودی‌های LoAF را تحت کلید longAnimationFrameEntries از شیء attribution نمایش می‌دهد. جدول زیر چند بخش کلیدی از داده‌هایی را که می‌توانید در هر ورودی LoAF پیدا کنید، فهرست می‌کند:

کلید شیء ورودی LoAF داده‌ها
duration مدت زمان فریم انیمیشن بلند، تا زمانی که طرح‌بندی تمام شده باشد، اما شامل نقاشی و ترکیب‌بندی نمی‌شود.
blockingDuration کل مدت زمانی که مرورگر در فریم به دلیل وظایف طولانی قادر به پاسخگویی سریع نبوده است. این زمان مسدود شدن می‌تواند شامل وظایف طولانی اجرای جاوا اسکریپت و همچنین هرگونه وظیفه رندر طولانی بعدی در فریم باشد.
firstUIEventTimestamp مهر زمانیِ زمانِ صف‌بندیِ رویداد در طول فریم. برای تشخیص شروع تأخیر ورودی یک تعامل مفید است.
startTime مهر زمانی شروع فریم.
renderStart زمانی که کار رندرینگ برای فریم آغاز شد. این شامل هرگونه فراخوانی requestAnimationFrame (و در صورت لزوم، فراخوانی ResizeObserver ) می‌شود، اما احتمالاً قبل از شروع هرگونه کار مربوط به استایل/لایه‌بندی.
styleAndLayoutStart چه زمانی کار بر روی سبک/طرح‌بندی در فریم انجام می‌شود. می‌تواند در تشخیص مدت زمان کار بر روی سبک/طرح‌بندی هنگام محاسبه در سایر مهرهای زمانی موجود مفید باشد.
scripts آرایه‌ای از آیتم‌ها که حاوی اطلاعات انتساب اسکریپت هستند و به INP صفحه کمک می‌کنند.
تجسم یک فریم انیمیشن بلند طبق مدل LoAF.
نموداری از زمان‌بندی‌های یک فریم انیمیشن طولانی طبق API مربوط به LoAF (منهای blockingDuration ).

تمام این اطلاعات می‌توانند چیزهای زیادی در مورد اینکه چه چیزی باعث کندی یک تعامل می‌شود به شما بگویند—اما آرایه scripts که ورودی‌های LoAF نشان می‌دهند باید مورد توجه ویژه باشند:

کلید شیء انتساب اسکریپت داده‌ها
invoker فراخوانی‌کننده. این می‌تواند بسته به نوع فراخوانی‌کننده که در ردیف بعدی توضیح داده شده است، متفاوت باشد. نمونه‌هایی از فراخوانی‌کننده‌ها می‌توانند مقادیری مانند 'IMG#id.onload' ، 'Window.requestAnimationFrame' یا 'Response.json.then' باشند.
invokerType نوع فراخوانی‌کننده. می‌تواند 'user-callback' ، 'event-listener' ، 'resolve-promise' ، 'reject-promise' ، 'classic-script' یا 'module-script' باشد.
sourceURL آدرس اینترنتی (URL) اسکریپتی که فریم انیمیشن بلند از آن سرچشمه گرفته است.
sourceCharPosition موقعیت کاراکتر در اسکریپت که توسط sourceURL شناسایی شده است.
sourceFunctionName نام تابع در اسکریپت شناسایی شده.

هر ورودی در این آرایه شامل داده‌های نمایش داده شده در این جدول است که اطلاعاتی در مورد اسکریپتی که مسئول کندی تعامل بوده است و نحوه‌ی مسئولیت آن ارائه می‌دهد.

اندازه‌گیری و شناسایی علل رایج پشت تعاملات کند

برای اینکه ایده‌ای از نحوه استفاده از این اطلاعات به شما بدهیم، این راهنما به شما نشان می‌دهد که چگونه می‌توانید از داده‌های LoAF موجود در کتابخانه web-vitals برای تعیین برخی از دلایل کندی تعاملات استفاده کنید.

مدت زمان طولانی پردازش

مدت زمان پردازش یک تعامل، مدت زمانی است که طول می‌کشد تا فراخوانی‌های ثبت‌شده‌ی کنترل‌کننده‌ی رویدادِ تعامل، اجرا و تکمیل شوند و هر اتفاق دیگری که ممکن است بین آنها رخ دهد. مدت زمان‌های پردازش بالا توسط کتابخانه‌ی web-vitals نمایش داده می‌شوند:

import {onINP} from 'web-vitals/attribution';

onINP(({name, value, attribution}) => {
  const {processingDuration} = attribution; // 512.5
});

طبیعی است که فکر کنید علت اصلی کندی تعامل این است که کد کنترل‌کننده رویداد شما برای اجرا خیلی طول کشیده است، اما همیشه اینطور نیست! وقتی تأیید کردید که مشکل از این است، می‌توانید با داده‌های LoAF عمیق‌تر بررسی کنید:

import {onINP} from 'web-vitals/attribution';

onINP(({name, value, attribution}) => {
  const {processingDuration} = attribution; // 512.5

  // Get the longest script from LoAF covering `processingDuration`:
  const loaf = attribution.longAnimationFrameEntries.at(-1);
  const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];

  if (script) {
    // Get attribution for the long-running event handler:
    const {invokerType} = script;        // 'event-listener'
    const {invoker} = script;            // 'BUTTON#update.onclick'
    const {sourceURL} = script;          // 'https://example.com/app.js'
    const {sourceCharPosition} = script; // 83
    const {sourceFunctionName} = script; // 'update'
  }
});

همانطور که در قطعه کد قبلی مشاهده می‌کنید، می‌توانید با داده‌های LoAF کار کنید تا علت دقیق یک تعامل با مقادیر بالای مدت زمان پردازش را ردیابی کنید، از جمله:

  • عنصر و شنونده‌ی رویداد ثبت‌شده‌ی آن.
  • فایل اسکریپت - و جایگاه کاراکتر درون آن - که شامل کد مدیریت رویداد طولانی مدت است.
  • نام تابع.

این نوع داده‌ها بسیار ارزشمند هستند. دیگر نیازی نیست که برای فهمیدن اینکه دقیقاً کدام تعامل - یا کدام یک از کنترل‌کننده‌های رویداد آن - مسئول مقادیر بالای مدت زمان پردازش بوده‌اند، زحمت زیادی بکشید. همچنین، از آنجایی که اسکریپت‌های شخص ثالث اغلب می‌توانند کنترل‌کننده‌های رویداد خود را ثبت کنند، می‌توانید تعیین کنید که آیا کد شما مسئول بوده است یا خیر! برای کدی که بر آن کنترل دارید، باید بهینه‌سازی وظایف طولانی را بررسی کنید.

تأخیرهای ورودی طولانی

اگرچه مدیریت‌کننده‌های رویداد طولانی‌مدت رایج هستند، بخش‌های دیگری از تعامل نیز وجود دارند که باید در نظر گرفته شوند. یک بخش قبل از مدت زمان پردازش رخ می‌دهد که به عنوان تأخیر ورودی شناخته می‌شود. این زمان از زمانی است که کاربر تعامل را آغاز می‌کند تا لحظه‌ای که فراخوانی‌های مدیریت‌کننده رویداد آن شروع به اجرا می‌کنند و زمانی اتفاق می‌افتد که نخ اصلی در حال پردازش یک کار دیگر است. ساختار attribution کتابخانه web-vitals می‌تواند مدت تأخیر ورودی برای یک تعامل را به شما بگوید:

import {onINP} from 'web-vitals/attribution';

onINP(({name, value, attribution}) => {
  const {inputDelay} = attribution; // 125.59439536
});

اگر متوجه شدید که برخی از تعاملات تأخیر ورودی بالایی دارند، باید بفهمید که در زمان تعامل چه اتفاقی در صفحه افتاده که باعث تأخیر ورودی طولانی شده است - و این اغلب به این بستگی دارد که آیا تعامل هنگام بارگذاری صفحه رخ داده است یا پس از آن.

موقع لود صفحه بود؟

رشته اصلی اغلب در زمان بارگذاری صفحه، شلوغ‌ترین بخش است. در این مدت، انواع وظایف در صف پردازش قرار می‌گیرند و اگر کاربر در حین انجام این کارها سعی در تعامل با صفحه داشته باشد، می‌تواند تعامل را به تأخیر بیندازد. صفحاتی که جاوا اسکریپت زیادی بارگذاری می‌کنند، می‌توانند کار کامپایل و ارزیابی اسکریپت‌ها و همچنین اجرای توابعی را که صفحه را برای تعامل کاربر آماده می‌کنند، آغاز کنند. اگر کاربر هنگام انجام این فعالیت تعامل داشته باشد، این کار می‌تواند مانع شود و می‌توانید بفهمید که آیا این مورد برای کاربران وب‌سایت شما نیز صدق می‌کند یا خیر:

import {onINP} from 'web-vitals/attribution';

onINP(({name, value, attribution}) => {
  const {inputDelay} = attribution; // 125.59439536

  // Get the longest script from the first LoAF entry:
  const loaf = attribution.longAnimationFrameEntries[0];
  const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];

  if (script) {
    // Invoker types can describe if script eval blocked the main thread:
    const {invokerType} = script;    // 'classic-script' | 'module-script'
    const {sourceLocation} = script; // 'https://example.com/app.js'
  }
});

اگر این داده‌ها را در فیلد ثبت کنید و تأخیرهای ورودی بالا و انواع فراخوانی‌کننده‌های 'classic-script' یا 'module-script' را مشاهده کنید، می‌توان گفت که اسکریپت‌های سایت شما زمان زیادی برای ارزیابی نیاز دارند و به اندازه کافی نخ اصلی را مسدود می‌کنند تا تعاملات را به تأخیر بیندازند. می‌توانید این زمان مسدود شدن را با تقسیم اسکریپت‌های خود به بسته‌های کوچک‌تر کاهش دهید، بارگذاری کدهای بلااستفاده اولیه را به زمان دیگری موکول کنید و سایت خود را برای یافتن کدهای بلااستفاده‌ای که می‌توانید به‌طور کامل حذف کنید، بررسی کنید.

بعد از لود صفحه بود؟

اگرچه تأخیرهای ورودی اغلب هنگام بارگذاری صفحه رخ می‌دهند، اما این احتمال نیز وجود دارد که این تأخیرها پس از بارگذاری صفحه و به دلیل کاملاً متفاوتی رخ دهند. دلایل رایج تأخیرهای ورودی پس از بارگذاری صفحه می‌تواند کدی باشد که به دلیل فراخوانی قبلی setInterval به صورت دوره‌ای اجرا می‌شود، یا حتی فراخوانی‌های رویدادی که قبلاً برای اجرا در صف قرار گرفته‌اند و هنوز در حال پردازش هستند.

import {onINP} from 'web-vitals/attribution';

onINP(({name, value, attribution}) => {
  const {inputDelay} = attribution; // 125.59439536

  // Get the longest script from the first LoAF entry:
  const loaf = attribution.longAnimationFrameEntries[0];
  const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];

  if (script) {
    const {invokerType} = script;        // 'user-callback'
    const {sourceURL} = script;          // 'https://example.com/app.js'
    const {sourceCharPosition} = script; // 83
    const {sourceFunctionName} = script; // 'update'
  }
});

همانطور که در مورد عیب‌یابی مقادیر بالای مدت زمان پردازش نیز صادق است، تأخیرهای ورودی بالا به دلایلی که قبلاً ذکر شد، داده‌های دقیقی از انتساب اسکریپت به شما ارائه می‌دهد. با این حال، تفاوت این است که نوع فراخوانی‌کننده بر اساس ماهیت کاری که تعامل را به تأخیر انداخته است، تغییر خواهد کرد:

  • 'user-callback' نشان می‌دهد که وظیفه مسدود کردن از setInterval ، setTimeout یا حتی requestAnimationFrame بوده است.
  • 'event-listener' نشان می‌دهد که وظیفه مسدود کردن از ورودی قبلی بوده که در صف قرار گرفته و هنوز در حال پردازش است.
  • 'resolve-promise' و 'reject-promise' به این معنی است که وظیفه مسدود کردن از یک کار ناهمزمان بوده که قبلاً شروع شده و در زمانی که کاربر سعی در تعامل با صفحه داشته، حل یا رد شده و تعامل را به تأخیر انداخته است.

در هر صورت، داده‌های مربوط به انتساب اسکریپت به شما این حس را می‌دهد که از کجا باید جستجو را شروع کنید، و اینکه آیا تأخیر ورودی به دلیل کد خودتان بوده یا اسکریپت شخص ثالث.

تأخیرهای طولانی در ارائه

تأخیرهای ارائه، آخرین مرحله از یک تعامل هستند و از زمانی که کنترل‌کننده‌های رویداد تعامل به پایان می‌رسند، تا نقطه‌ای که فریم بعدی ترسیم شده است، شروع می‌شوند. این تأخیرها زمانی رخ می‌دهند که کار در یک کنترل‌کننده رویداد به دلیل یک تعامل، وضعیت بصری رابط کاربری را تغییر می‌دهد. همانند مدت زمان پردازش و تأخیرهای ورودی، کتابخانه web-vitals می‌تواند به شما بگوید که تأخیر ارائه برای یک تعامل چقدر بوده است:

import {onINP} from 'web-vitals/attribution';

onINP(({name, value, attribution}) => {
  const {presentationDelay} = attribution; // 113.32307691
});

اگر این داده‌ها را ثبت کنید و شاهد تأخیرهای زیاد در ارائه تعاملات مرتبط با INP وب‌سایت خود باشید، عوامل مؤثر می‌توانند متفاوت باشند، اما در اینجا چند دلیل برای بررسی وجود دارد.

کارهای گران‌قیمت در زمینه سبک و چیدمان

تأخیرهای طولانی در ارائه ممکن است ناشی از محاسبه مجدد سبک و کار طرح‌بندی پرهزینه باشد که به دلایل مختلفی از جمله انتخابگرهای پیچیده CSS و اندازه‌های بزرگ DOM ایجاد می‌شود. می‌توانید مدت زمان این کار را با زمان‌بندی‌های LoAF که در کتابخانه web-vitals ارائه شده است، اندازه‌گیری کنید:

import {onINP} from 'web-vitals/attribution';

onINP(({name, value, attribution}) => {
  const {presentationDelay} = attribution; // 113.32307691

  // Get the longest script from the last LoAF entry:
  const loaf = attribution.longAnimationFrameEntries.at(-1);
  const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];

  // Get necessary timings:
  const {startTime} = loaf; // 2120.5
  const {duration} = loaf;  // 1002

  // Figure out the ending timestamp of the frame (approximate):
  const endTime = startTime + duration; // 3122.5

  // Get the start timestamp of the frame's style/layout work:
  const {styleAndLayoutStart} = loaf; // 3011.17692309

  // Calculate the total style/layout duration:
  const styleLayoutDuration = endTime - styleAndLayoutStart; // 111.32307691

  if (script) {
    // Get attribution for the event handler that triggered
    // the long-running style and layout operation:
    const {invokerType} = script;        // 'event-listener'
    const {invoker} = script;            // 'BUTTON#update.onclick'
    const {sourceURL} = script;          // 'https://example.com/app.js'
    const {sourceCharPosition} = script; // 83
    const {sourceFunctionName} = script; // 'update'
  }
});

LoAF مدت زمان کار طراحی و صفحه‌آرایی برای یک فریم را به شما نمی‌گوید، اما زمان شروع آن را به شما می‌گوید. با این مهر زمانی شروع، می‌توانید از داده‌های دیگر LoAF برای محاسبه مدت زمان دقیق آن کار با تعیین زمان پایان فریم و کم کردن مهر زمانی شروع کار طراحی و صفحه‌آرایی از آن استفاده کنید.

فراخوانی‌های طولانی مدت requestAnimationFrame

یکی از دلایل احتمالی تأخیرهای طولانی در ارائه، کار بیش از حد انجام شده در فراخوانی requestAnimationFrame است. محتویات این فراخوانی پس از پایان اجرای کنترل‌کننده‌های رویداد، اما درست قبل از محاسبه مجدد سبک و کارهای مربوط به طرح‌بندی اجرا می‌شوند.

اگر کار انجام شده در این فراخوانی‌های برگشتی پیچیده باشد، تکمیل آنها می‌تواند زمان قابل توجهی طول بکشد. اگر گمان می‌کنید که مقادیر بالای تأخیر در ارائه به دلیل کاری است که با requestAnimationFrame انجام می‌دهید، می‌توانید از داده‌های LoAF که توسط کتابخانه web-vitals ارائه می‌شود، برای شناسایی این سناریوها استفاده کنید:

onINP(({name, value, attribution}) => {
  const {presentationDelay} = attribution; // 543.1999999880791

  // Get the longest script from the last LoAF entry:
  const loaf = attribution.longAnimationFrameEntries.at(-1);
  const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];

  // Get the render start time and when style and layout began:
  const {renderStart} = loaf;         // 2489
  const {styleAndLayoutStart} = loaf; // 2989.5999999940395

  // Calculate the `requestAnimationFrame` callback's duration:
  const rafDuration = styleAndLayoutStart - renderStart; // 500.59999999403954

  if (script) {
    // Get attribution for the event handler that triggered
    // the long-running requestAnimationFrame callback:
    const {invokerType} = script;        // 'user-callback'
    const {invoker} = script;            // 'FrameRequestCallback'
    const {sourceURL} = script;          // 'https://example.com/app.js'
    const {sourceCharPosition} = script; // 83
    const {sourceFunctionName} = script; // 'update'
  }
});

اگر می‌بینید که بخش قابل توجهی از زمان تأخیر ارائه صرف فراخوانی requestAnimationFrame می‌شود، مطمئن شوید کاری که در این فراخوانی‌ها انجام می‌دهید محدود به انجام کاری است که منجر به به‌روزرسانی واقعی رابط کاربری می‌شود. هر کار دیگری که به DOM یا به‌روزرسانی استایل‌ها مربوط نباشد، بی‌جهت باعث تأخیر در رنگ‌آمیزی فریم بعدی می‌شود، بنابراین مراقب باشید!

نتیجه‌گیری

داده‌های میدانی بهترین منبع اطلاعاتی هستند که می‌توانید هنگام درک اینکه کدام تعاملات برای کاربران واقعی در این زمینه مشکل‌ساز هستند، از آنها استفاده کنید. با تکیه بر ابزارهای جمع‌آوری داده‌های میدانی مانند کتابخانه جاوا اسکریپت web-vitals (یا یک ارائه‌دهنده RUM)، می‌توانید با اطمینان بیشتری در مورد اینکه کدام تعاملات مشکل‌سازتر هستند، تصمیم بگیرید و سپس به سراغ بازتولید تعاملات مشکل‌ساز در آزمایشگاه بروید و سپس به رفع آنها بپردازید.

تصویر قهرمان از Unsplash ، اثر فدریکو رسپینی .