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

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

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

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

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

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

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

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

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

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

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

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

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

توافق المتصفّح

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

المصدر

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

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

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

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

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

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

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

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

Long Animation Frames API (LoAF)

دعم المتصفح

  • Chrome: 123.
  • Edge:‏ 123.
  • Firefox: غير مدعوم.
  • Safari: غير متاح.

المصدر

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

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

مفتاح عنصر إدخال 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 التي تعرضها مكتبة 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.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)، يمكنك أن تكون أكثر ثقة بشأن التفاعلات الأكثر تسببًا في المشاكل، ثم انتقِل إلى إعادة إنتاج التفاعلات التي تتضمّن مشاكل في الميزة الاختبارية ثم ابدأ بإصلاحها.

الصورة الرئيسية من Unsplash، لأحد أعمال Federico Respini.