البحث عن التفاعلات البطيئة في الحقل

تعرَّف على كيفية العثور على التفاعلات البطيئة في بيانات حقل موقعك الإلكتروني كي تتمكّن من العثور على فرص لتحسين سرعة عرض التفاعل مع الصفحة التالية.

بيانات الحقل هي بيانات توضّح لك تجربة المستخدمين الفعلية لموقعك الإلكتروني. وهو يسلّط الضوء على المشاكل التي لا يمكن رصدها في بيانات المختبر وحدها. بالنسبة إلى مدى استجابة الصفحة لتفاعلات المستخدم (INP)، تكون البيانات الميدانية ضرورية لتحديد التفاعلات البطيئة، كما أنّها توفّر مؤشرات حيوية لمساعدتك في إصلاحها.

ستتعرّف في هذا الدليل على طريقة تقييم INP على موقعك الإلكتروني بسرعة باستخدام البيانات الميدانية في تقرير تجربة المستخدم على Chrome (CrUX) لمعرفة ما إذا كان موقعك الإلكتروني يواجه مشاكل في هذا المقياس. بعد ذلك، ستتعرف على طريقة استخدام إصدار تحديد المصدر في مكتبة JavaScript لمؤشرات أداء الويب، والإحصاءات الجديدة التي توفِّرها من خلال Long Animation Frames API (LoAF)، لجمع بيانات الحقول وتفسيرها للتفاعلات البطيئة على موقعك الإلكتروني.

البدء باستخدام CrUX لتقييم مدى استجابة الصفحة لتفاعلات المستخدم (INP) على موقعك الإلكتروني

إذا كنت لا تجمع بيانات ميدانية من مستخدمي موقعك الإلكتروني، قد تكون CrUX نقطة انطلاق جيدة. يجمع تقرير تجربة المستخدم على Chrome بيانات الحقول من مستخدمي Chrome الحقيقيين الذين وافقوا على إرسال بيانات القياس عن بُعد.

تظهر بيانات CrUX في عدد من المناطق المختلفة، وتعتمد على نطاق المعلومات التي تبحث عنها. يمكن أن توفّر CrUX بيانات عن مدى استجابة الصفحة لتفاعلات المستخدم (INP) وغيره من مؤشرات "Core Web Vitals" للأغراض التالية:

  • صفحات فردية ومصادر كاملة باستخدام إحصاءات PageSpeed
  • أنواع الصفحات. على سبيل المثال، العديد من مواقع التجارة الإلكترونية لديها نوعان "صفحة تفاصيل المنتج" و"صفحات قائمة المنتجات". يمكنك الحصول على بيانات CrUX لأنواع الصفحات الفريدة من خلال Search Console.

يمكنك إدخال عنوان URL لموقعك الإلكتروني في "إحصاءات PageSpeed" كنقطة بداية. بعد إدخال عنوان URL، سيتم عرض البيانات الخاصة به، إن كانت متاحة، لمقاييس متعدّدة، بما في ذلك INP. يمكنك أيضًا استخدام مفاتيح التبديل للاطّلاع على قيم INP لسمات الأجهزة الجوّالة وأجهزة الكمبيوتر المكتبي.

بيانات الحقل المعروضة من خلال CrUX في "إحصاءات PageSpeed"، والتي تُظهر LCP وINP وCLS في مؤشرات Core Web Vitals الثلاثة وTTFB وFCP كمقاييس تشخيصية، وFID كمقياس تم إيقاف مؤشرات Core Web Vitals فيه
قراءة بيانات CrUX كما هو موضح في "إحصاءات PageSpeed". في هذا المثال، يحتاج مقياس INP (مدى استجابة الصفحة لتفاعلات المستخدم) (INP) إلى تحسين.

هذه البيانات مفيدة لأنها تخبرك إذا كانت لديك مشكلة. ومع ذلك، ما لا تستطيع أداة CrUX فعله هو إخبارك بأسباب حدوث المشاكل. يتوفّر العديد من حلول "تتبُّع المستخدم الفعلي" (RUM) التي ستساعدك على جمع بيانات الحقول الخاصة بك من مستخدمي موقعك الإلكتروني لمساعدتك في الإجابة عن ذلك، أحد الخيارات المتاحة هو جمع بيانات الحقل بنفسك باستخدام مكتبة JavaScript لمؤشرات أداء الويب.

جمع بيانات الحقول باستخدام مكتبة JavaScript web-vitals

مكتبة JavaScript web-vitals هي نص برمجي يمكنك تحميله على موقعك الإلكتروني لجمع بيانات الحقول من مستخدمي الموقع الإلكتروني. ويمكنك استخدامه لتسجيل عدد من المقاييس، بما في ذلك INP في المتصفّحات المتوافقة.

دعم المتصفح

  • Chrome: 96.
  • الحافة: 96.
  • Firefox: غير مدعوم.
  • Safari: غير متاح.

المصدر

يمكن استخدام الإصدار العادي من مكتبة "مؤشرات أداء الويب" للحصول على بيانات 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. وهنا يأتي دور إصدار الإحالة لمكتبة مؤشرات أداء الويب.

تحقيق المزيد من خلال إنشاء الإحالة في مكتبة مؤشرات أداء الويب

يعرِض إنشاء تحديد المصدر في مكتبة "مؤشرات أداء الويب" بيانات إضافية يمكنك الحصول عليها من المستخدمين في هذا المجال لمساعدتك في تحديد وحلّ المشاكل المتعلّقة بالتفاعلات التي تؤثّر في مقياس "مدى استجابة الصفحة لتفاعلات المستخدم" (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
});
طريقة ظهور سجلّات وحدة التحكّم من مكتبة مؤشرات أداء الويب تعرض وحدة التحكّم في هذا المثال اسم المقياس (INP)، وقيمة INP (56)، حيث تتوفّر هذه القيمة ضمن حدود INP (الجيدة)، ومعلومات المعلومات المختلفة المعروضة في عنصر تحديد المصدر، بما في ذلك الإدخالات من واجهة برمجة التطبيقات Long Animation Frames API.
طريقة ظهور البيانات من مكتبة "مؤشرات أداء الويب" في وحدة التحكّم.

بالإضافة إلى مقياس INP للصفحة نفسها، يوفّر إنشاء تحديد المصدر الكثير من البيانات التي يمكنك استخدامها للمساعدة في فهم أسباب التفاعلات البطيئة، بما في ذلك الجزء الذي يجب التركيز عليه من التفاعل. يمكن أن تساعدك في الإجابة عن أسئلة مهمة مثل:

  • "هل تفاعل المستخدم مع الصفحة أثناء تحميلها؟"
  • "هل تم تشغيل معالِجات أحداث التفاعل لفترة طويلة؟"
  • "هل تم تأخير رمز معالج أحداث التفاعل عن البدء؟ إذا كان الأمر كذلك، فما الذي كان يحدث أيضًا في سلسلة المحادثات الرئيسية في ذلك الوقت؟"
  • "هل تسبّب التفاعل في عرض الكثير من أعمال العرض التي أدّت إلى تأخير عرض الإطار التالي؟"

يعرض الجدول التالي بعض بيانات تحديد المصدر الأساسية التي يمكنك الحصول عليها من المكتبة، والتي يمكن أن تساعدك في معرفة بعض الأسباب عالية المستوى للتفاعلات البطيئة على موقعك الإلكتروني:

مفتاح الكائن attribution البيانات
interactionTarget أداة اختيار لغة CSS تشير إلى العنصر الذي أدّى إلى إنشاء قيمة INP للصفحة، مثل button#save.
interactionType نوع التفاعل، إما من النقرات أو النقرات أو إدخالات لوحة المفاتيح.
inputDelay* تأخير الإدخال للتفاعل.
processingDuration* يشير ذلك إلى الوقت منذ بدء تشغيل أداة معالجة الحدث الأول استجابةً لتفاعل المستخدم إلى حين انتهاء معالجة جميع أدوات معالجة الأحداث.
presentationDelay* مهلة العرض التقديمي للتفاعل، وهي تبدأ من وقت انتهاء معالِجات الأحداث إلى وقت عرض الإطار التالي.
longAnimationFrameEntries* الإدخالات من LoAF المرتبطة بالتفاعل. اطّلِع على التالي للحصول على معلومات إضافية.
*الجديد في الإصدار 4

بدءًا من الإصدار 4 من مكتبة "مؤشرات أداء الويب"، يمكنك الحصول على إحصاءات أكثر تفصيلاً حول التفاعلات التي تسبب المشاكل من خلال البيانات التي توفِّرها هذه البيانات من خلال تقسيمات مراحل مقياس INP (مهلة الإدخال ومدة المعالجة ومهلة العرض التقديمي) وواجهة برمجة تطبيقات إطارات الصور المتحركة الطويلة (LoAF).

The Long Animation Frames API (LoAF)

دعم المتصفح

  • Chrome: 123.
  • الحافة: 123.
  • Firefox: غير مدعوم.
  • Safari: غير متاح.

المصدر

يعد تصحيح أخطاء التفاعلات باستخدام بيانات الميدان مهمة صعبة. مع ذلك، أصبح من الممكن الآن الحصول على إحصاءات أفضل عن الأسباب وراء بطء التفاعلات مع البيانات المتوفّرة من خلال LoAF، إذ يعرض LoAF عددًا من التوقيتات التفصيلية وبيانات أخرى يمكنك استخدامها لتحديد الأسباب الدقيقة، والأهم من ذلك، تحديد مصدر المشكلة في رمز موقعك الإلكتروني.

يعرض إصدار تحديد المصدر الخاص بمكتبة "مؤشرات أداء الويب" مصفوفة من إدخالات LoAF ضِمن المفتاح longAnimationFrameEntries للعنصر attribution. يسرد الجدول التالي بعض البيانات الرئيسية التي يمكنك العثور عليها في كل إدخال من إدخالات LoAF:

مفتاح كائن إدخال LoAF البيانات
duration مدة إطار الصورة المتحركة الطويل، حتى وقت انتهاء التنسيق، ولكن باستثناء الرسم والتركيب.
blockingDuration إجمالي الوقت الذي لم يتمكّن فيه المتصفّح من الاستجابة بسرعة في الإطار بسبب المهام الطويلة وقد يشمل وقت الحظر هذا المهام التي تستغرق وقتًا طويلاً لتشغيل JavaScript، بالإضافة إلى أي مهمة عرض طويلة لاحقة في الإطار.
firstUIEventTimestamp الطابع الزمني لوقت إضافة الحدث إلى قائمة الانتظار أثناء عرض الإطار وتفيد هذه الميزة في معرفة بداية مهلة الإدخال الخاصة بالتفاعل.
startTime الطابع الزمني لبدء الإطار
renderStart عند بدء عرض الإطار ويشمل ذلك أي استدعاءات requestAnimationFrameResizeObserver استدعاء إن أمكن)، ولكن قد يكون ذلك قبل بدء أي عمل على النمط أو التنسيق.
styleAndLayoutStart عندما يكون النمط/التنسيق يعمل في الإطار. يمكن أن تكون مفيدة في معرفة طول النمط/التنسيق عند تحديد طوابع زمنية أخرى متاحة.
scripts مصفوفة من العناصر التي تحتوي على معلومات إحالة النص البرمجي التي تساهم في مقياس INP للصفحة.
تصور لإطار رسوم متحركة طويل وفقًا لنموذج LoAF.
مخطّط بياني لتوقيتات إطار رسوم متحركة طويل وفقًا لواجهة برمجة التطبيقات LoAF API (مطروحًا منه 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 لتحديد بعض الأسباب وراء بطء التفاعلات.

مُدد معالجة طويلة

مدة معالجة أحد التفاعلات هي الوقت الذي يستغرقه تنفيذ استدعاءات معالج الحدث المسجَّل للتفاعل حتى الاكتمال وأي شيء آخر قد يحدث بينهما. تعرض مكتبة مؤشرات أداء الويب مُدد معالجة عالية:

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.sort((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 لتتبُّع السبب الدقيق وراء التفاعل ذي القيم العالية لمدة المعالجة، بما في ذلك:

  • العنصر وأداة معالجة الأحداث المسجَّلة
  • يحتوي ملف النص البرمجي - وموضع الحرف بداخله - على الرمز البرمجي لمعالِج الحدث الذي تم إنشاؤه منذ فترة طويلة.
  • تمثّل هذه السمة اسم الدالة.

هذا النوع من البيانات لا يقدر بثمن. لم تعُد بحاجة إلى اتخاذ الإجراءات اللازمة لمعرفة التفاعل بالضبط، أو معالِجات الأحداث الخاصة به، التي كانت مسؤولة عن قيم مدة المعالجة المرتفعة. ونظرًا لأن النصوص البرمجية التابعة لجهات خارجية يمكنها في كثير من الأحيان تسجيل معالِجات الأحداث الخاصة بها، يمكنك تحديد ما إذا كانت التعليمة البرمجية هي المسؤولة عن ذلك أم لا! بالنسبة إلى الرمز الذي يمكنك التحكّم فيه، ستحتاج إلى النظر في تحسين المهام الطويلة.

تأخير طويل في الإدخال

وعلى الرغم من أنّ معالِجات الأحداث الطويلة الأمد هي الحالات الشائعة، هناك أجزاء أخرى من التفاعل يجب أخذها في الاعتبار. يحدث جزء واحد قبل مدة المعالجة، وهو ما يُعرف باسم تأخير الإدخال. يشير هذا إلى الوقت الذي يبدأ فيه المستخدم التفاعل، إلى أن يبدأ تشغيل عمليات معاودة الاتصال بمعالج الأحداث، ويحدث عندما تعالج سلسلة المحادثات الرئيسية مهمة أخرى. يمكن أن يُطلعك إصدار تحديد المصدر في مكتبة "مؤشرات أداء الويب" على مدة تأخير الإدخال لأحد التفاعلات:

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

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

إذا لاحظت أنّ بعض التفاعلات تعاني من تأخير كبير في الإدخال، ستحتاج إلى معرفة ما كان يحدث على الصفحة في وقت التفاعل الذي تسبّب في حدوث تأخير طويل في الإدخال، وغالبًا ما يعود ذلك إلى ما إذا كان التفاعل قد حدث أثناء تحميل الصفحة أو بعد ذلك.

هل حدثت أثناء تحميل الصفحة؟

غالبًا ما تكون سلسلة التعليمات الرئيسية أكثر ازدحامًا أثناء تحميل الصفحة. خلال هذا الوقت، يتم وضع جميع أنواع المهام في قائمة الانتظار ومعالجتها، وإذا حاول المستخدم التفاعل مع الصفحة أثناء تنفيذ كل هذا العمل، فقد يؤدي ذلك إلى تأخير التفاعل. يمكن للصفحات التي تحمّل الكثير من JavaScript أن تبدأ العمل على تجميع النصوص البرمجية وتقييمها، بالإضافة إلى تنفيذ الدوال التي تجعل الصفحة جاهزة لتفاعلات المستخدم. يمكن أن يعيق هذا الإجراء إذا تصادف أن تفاعل المستخدم عند حدوث هذا النشاط، ويمكنك معرفة ما إذا كان هذا هو الحال بالنسبة لمستخدمي موقعك الإلكتروني:

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.sort((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.sort((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' أنّ مهمة الحظر كانت من بعض الأعمال غير المتزامنة التي تم تنفيذها سابقًا، وتم حلها أو رفضها في وقت حاول فيه المستخدم التفاعل مع الصفحة، ما أدى إلى تأخير التفاعل.

في أي حالة، ستمنحك بيانات إحالة النص البرمجي فكرة عن المكان الذي يجب أن تبدأ فيه البحث، وما إذا كان تأخير الإدخال بسبب الرمز الخاص بك، أو نص برمجي تابع لجهة خارجية.

تأخير طويل في العرض

تمثِّل تأخيرات العروض التقديمية المرحلة الأخيرة من التفاعل، وتبدأ عند انتهاء معالِجات أحداث التفاعل، حتى النقطة التي تم فيها عرض الإطار التالي. تحدث عندما يغير العمل في معالج أحداث بسبب تفاعل الحالة المرئية لواجهة المستخدم. كما هو الحال مع مُدد المعالجة وحالات تأخّر الإدخال، يمكن أن توضّح لك مكتبة مؤشرات أداء الويب مدة تأخّر العرض التقديمي للتفاعل:

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

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

إذا سجّلت هذه البيانات ولاحظت حالات تأخير عالية في عرض التفاعلات التي تساهم في مقياس INP على موقعك الإلكتروني، يمكن أن تختلف الأسباب المحتمَلة، ولكن إليك بعض الأسباب التي قد تؤدي إلى توخّي الحذر.

الأسلوب والتخطيط باهظ الثمن

قد تكون حالات التأخير الطويلة في العرض التقديمي إعادة حساب للنمط وتخطيط باهظة الثمن تنشأ عن عدد من الأسباب، بما في ذلك أدوات اختيار لغة CSS المعقّدة وأحجام DOM الكبيرة. يمكنك قياس مدة هذا العمل من خلال توقيتات LoAF المعروضة في مكتبة مؤشرات أداء الويب:

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.sort((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 التي تعرضها مكتبة مؤشرات أداء الويب لتحديد السيناريوهات التالية:

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.sort((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) أو يؤدي إلى تحديث الأنماط، فقد يؤدي ذلك إلى تأخير عرض الإطار التالي بدون داعٍ.

الخاتمة

البيانات الميدانية هي أفضل مصدر للمعلومات يمكنك الاعتماد عليه عندما يتعلق الأمر بفهم التفاعلات التي تمثل مشكلة للمستخدمين الفعليين في هذا المجال. ومن خلال الاعتماد على أدوات جمع البيانات الميدانية، مثل مكتبة JavaScript لمؤشرات أداء الويب (أو موفّر خدمة RUM)، يمكنك أن تكون أكثر ثقة بشأن التفاعلات الأكثر تسببًا في المشاكل، ثم انتقِل إلى إعادة إنتاج التفاعلات التي تتضمّن مشاكل في الميزة الاختبارية ثم ابدأ بإصلاحها.

صورة رئيسية من Unسباش، من تأليف فيديريكو ريسبيني