واجهة برمجة التطبيقات لإطارات الصور المتحركة الطويلة

Long Animation Frames API (LoAF) هي تحديث لـ Long Tasks API لتقديم فهم أفضل لبطء تحديثات واجهة المستخدم. يمكن أن يكون ذلك مفيدًا لتحديد اللقطات البطيئة للرسوم المتحركة التي يُحتمل أن تؤثّر في مقياس مدى استجابة الصفحة لتفاعلات المستخدم (INP) ضمن "مؤشرات أداء الويب الأساسية" الذي يقيس مستوى الاستجابة، أو لتحديد أي مشاكل أخرى في واجهة المستخدم تؤثّر في سلاسة الأداء.

حالة واجهة برمجة التطبيقات

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

  • Chrome: 123
  • Edge: ‏ 123.
  • Firefox: غير متوافق
  • Safari: غير متوافق

المصدر

بعد مرحلة تجربة وتقييم من الإصدار 116 من Chrome إلى الإصدار 122 من Chrome، تم طرح LoAF API من الإصدار 123 من Chrome.

مقدّمة: Long Tasks API

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

  • Chrome: 58
  • ‫Edge: 79
  • Firefox: غير متوافق
  • Safari: غير متوافق

المصدر

واجهة برمجة التطبيقات Long Animation Frames API هي بديل لواجهة برمجة التطبيقات Long Tasks API التي كانت متاحة في Chrome منذ بعض الوقت (بدءًا من الإصدار 58). كما يوحي اسمها، تتيح لك Long Task API مراقبة المهام التي تستغرق وقتًا طويلاً، وهي المهام التي تشغل السلسلة الرئيسية لمدة 50 ملي ثانية أو أكثر. يمكن مراقبة المهام الطويلة باستخدام واجهة PerformanceLongTaskTiming، مع PeformanceObserver:

const observer = new PerformanceObserver((list) => {
  console.log(list.getEntries());
});

observer.observe({ type: 'longtask', buffered: true });

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

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

لذلك، عند محاولة تحسين وقت الاستجابة، غالبًا ما يكون الجهد الأول هو تنفيذ عملية تتبُّع للأداء والاطّلاع على المهام التي تستغرق وقتًا طويلاً. ويمكن إجراء ذلك من خلال أداة تدقيق مستندة إلى المختبر مثل Lighthouse (التي تتضمّن عملية تدقيق تجنُّب المهام التي تستغرق وقتًا طويلاً في سلسلة التعليمات الرئيسية)، أو من خلال الاطّلاع على المهام التي تستغرق وقتًا طويلاً في أدوات مطوّري البرامج في Chrome.

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

أوجه القصور في Long Tasks API

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

غالبًا ما تستخدِم أدوات "مراقبة المستخدِمين الفعليين" (RUM) هذه البيانات لرصد عدد المهام الطويلة أو مدّتها أو لتحديد الصفحات التي تحدث فيها، ولكن بدون التفاصيل الأساسية لسبب المهام الطويلة، يكون هذا الاستخدام محدودًا. لا تتضمّن Long Tasks API سوى نموذج تحديد مصدر أساسي، والذي يُعلمك في أفضل الأحوال بالحاوية التي حدثت فيها المهمة الطويلة (المستند من المستوى الأعلى أو <iframe>)، ولكن ليس النص البرمجي أو الدالة التي تم استدعاؤها، كما هو موضّح في إدخال نموذجي:

{
  "name": "unknown",
  "entryType": "longtask",
  "startTime": 31.799999997019768,
  "duration": 136,
  "attribution": [
    {
      "name": "unknown",
      "entryType": "taskattribution",
      "startTime": 0,
      "duration": 0,
      "containerType": "window",
      "containerSrc": "",
      "containerId": "",
      "containerName": ""
    }
  ]
}

لا تقدّم Long Tasks API أيضًا عرضًا كاملاً، لأنّها قد تستبعد أيضًا بعض المهام المهمة. تحدث بعض التعديلات، مثل المعالجة، في مهام منفصلة من المفترض أن يتم تضمينها مع التنفيذ السابق الذي أدّى إلى هذا التعديل لقياس "إجمالي العمل" لهذا التفاعل بدقة. لمزيد من التفاصيل حول قيود الاعتماد على المهام، يُرجى الاطّلاع على قسم "المشاكل التي تواجهها المهام الطويلة" في المقالة التوضيحية.

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

Long Animation Frames API

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

  • Chrome: 123
  • Edge: ‏ 123.
  • Firefox: غير متوافق
  • Safari: غير متوافق

المصدر

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

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

تُعدّ Long Animation Frames API طريقة بديلة لقياس عمل الحظر. بدلاً من قياس المهام الفردية، تقيس Long Animation Frames API اللقطات الطويلة للرسوم المتحركة، كما يشير اسمها. يحدث إطار الصورة المتحركة الطويل عندما يتأخّر تعديل العرض إلى أكثر من 50 ملي ثانية (وهو الحدّ الأقصى لواجهة برمجة التطبيقات Long Tasks API).

يتم قياس إطارات الصور المتحركة الطويلة من بداية المهام التي تتطلّب التقديم. إذا كانت المهمة الأولى في إطار الصورة المتحركة المحتملة التي تستغرق وقتًا طويلاً لا تتطلّب التقديم، يتم إنهاء إطار الصورة المتحركة الذي يستغرق وقتًا طويلاً عند اكتمال المهمة التي لا تتطلّب التقديم، ويتم بدء إطار صورة متحركة جديد يحتمل أن يستغرق وقتًا طويلاً مع المهمة التالية. لا يزال يتم تضمين لقطات الرسوم المتحركة الطويلة التي لا يتم عرضها في Long Animation Frames API عندما تكون مدتها أطول من 50 ملي ثانية (مع وقت renderStart يساوي 0) للسماح بقياس العمل الذي قد يؤدي إلى حدوث حظر.

يمكن رصد إطارات الرسوم المتحركة الطويلة بطريقة مشابهة للمهام الطويلة التي تتضمّن PerformanceObserver، ولكن بالاطّلاع على نوع long-animation-frame بدلاً من ذلك:

const observer = new PerformanceObserver((list) => {
  console.log(list.getEntries());
});

observer.observe({ type: 'long-animation-frame', buffered: true });

يمكن أيضًا البحث عن لقطات سابقة من الرسوم المتحركة الطويلة من المخطط الزمني للأداء على النحو التالي:

const loafs = performance.getEntriesByType('long-animation-frame');

ومع ذلك، هناك maxBufferSize لإدخالات الأداء يتم بعدها حذف الإدخالات الأحدث، لذا فإنّ نهج PerformanceObserver هو النهج المُقترَح. تم ضبط حجم ذاكرة التخزين المؤقت long-animation-frame على 200، وهو نفسه حجم ذاكرة التخزين المؤقت long-tasks.

مزايا الاطّلاع على الإطارات بدلاً من المهام

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

من المزايا الإضافية لهذا العرض البديل للمهام الطويلة هي إمكانية تقديم تفاصيل التوقيت للإطار بأكمله. بدلاً من تضمين startTime وduration فقط، مثل Long Tasks API، يتضمّن LoAF تقسيمًا أكثر تفصيلاً للأجزاء المختلفة من مدة عرض اللقطة.

الطوابع الزمنية للإطارات ومدتها

  • startTime: وقت بدء الصورة المتحركة التي تستغرق عرضها وقتًا طويلاً بالنسبة إلى وقت بدء التنقّل
  • duration: مدة عرض اللقطة الطويلة للحركة (باستثناء وقت العرض)
  • renderStart: وقت بدء دورة العرض، والذي يتضمّن requestAnimationFrame عمليات الاستدعاء وحساب التصميم والأسلوب وعمليات استدعاء مراقبَي تغيير الحجم والتداخل
  • styleAndLayoutStart: بداية الفترة الزمنية التي تمّ خلالها إجراء عمليات حسابية للأسلوب والتنسيق
  • firstUIEventTimestamp: وقت أوّل حدث لواجهة المستخدم (الماوس/لوحة المفاتيح وما إلى ذلك) الذي يجب معالجته خلال هذا الإطار.
  • blockingDuration: إجمالي المدة بالملي ثانية التي سيحظر فيها إطار الصورة المتحركة معالجة الإدخال أو المهام الأخرى ذات الأولوية العالية.

شرح حول blockingDuration

قد يتكوّن إطار الصورة المتحركة الطويل من عدد من المهام. يمثّل blockingDuration مجموع مدد المهام التي تزيد عن 50 ملي ثانية (بما في ذلك مدة العرض النهائي ضمن أطول مهمة).

على سبيل المثال، إذا كان إطارًا متحركة طويلاً يتألف من مهمتَين تستغرقان 55 مللي ثانية و65 مللي ثانية متبوعتين بعرض يستغرق 20 مللي ثانية، سيكون duration‏ 140 مللي ثانية تقريبًا مع blockingDuration‏ (55 - 50) + (65 + 20 - 50) = 40 مللي ثانية. لمدة 40 ملي ثانية خلال إطار الصورة المتحركة الذي تبلغ مدته 140 ملي ثانية، تم اعتبار الإطار محظورًا من معالجة الإدخال.

ما إذا كان يجب الاطّلاع على duration أو blockingDuration

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

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

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

توقيتات اللقطات

تسمح الطوابع الزمنية المذكورة سابقًا بتقسيم إطار الصورة المتحركة الطويل إلى أوقات:

التوقيت العملية الحسابية
وقت البدء startTime
وقت الانتهاء startTime + duration
مدة العمل renderStart ? renderStart - startTime : duration
مدة العرض renderStart ? (startTime + duration) - renderStart: 0
العرض: مدة التصميم المُسبَق styleAndLayoutStart ? styleAndLayoutStart - renderStart : 0
العرض: مدة الأسلوب والتنسيق styleAndLayoutStart ? (startTime + duration) - styleAndLayoutStart : 0

تحديد مصدر النصوص البرمجية بشكل أفضل

يتضمّن نوع الإدخال long-animation-frame بيانات تحديد مصدر أفضل لكل نص برمجي ساهم في إطار متحركة طويل (للنصوص البرمجية التي تزيد مدتها عن 5 مللي ثانية).

على غرار Long Tasks API، سيتم توفير ذلك في صفيف من إدخالات تحديد المصدر، يوضّح كل منها ما يلي:

  • ستؤدي كل من name وEntryType إلى عرض script.
  • invoker ذي معنى يشير إلى كيفية استدعاء النص البرمجي (على سبيل المثال، 'IMG#id.onload' أو 'Window.requestAnimationFrame' أو 'Response.json.then')
  • invokerType لنقطة دخول النص البرمجي:
    • user-callback: دالة استدعاء معروفة مسجّلة من واجهة برمجة تطبيقات لمنصّة الويب (مثل setTimeout وrequestAnimationFrame).
    • event-listener: مستمع لحدث منصة (مثل click أو load أو keyup)
    • resolve-promise: معالِج وعد من النظام الأساسي (على سبيل المثال، fetch(). يُرجى العلم أنّه في حال الوعد، يتم دمج جميع معالِجات الوعود نفسها معًا كـ "نص برمجي" واحد.).
    • reject-promise: وفقًا لما هو موضّح في resolve-promise، ولكن بالنسبة إلى الرفض.
    • classic-script: تقييم النص البرمجي (على سبيل المثال، <script> أو import())
    • module-script: الإجراء نفسه المُستخدَم في classic-script، ولكن لبرامج نصية للوحدات
  • افصل بيانات التوقيت لهذا النص البرمجي:
    • startTime: وقت استدعاء دالة الإدخال
    • duration: المدة بين startTime ووقت انتهاء معالجة قائمة المهام الصغيرة اللاحقة.
    • executionStart: الوقت بعد الترجمة.
    • forcedStyleAndLayoutDuration: إجمالي الوقت الذي تمّ إنفاقه في معالجة التنسيق والأسلوب الإجباريَين داخل هذه الدالة (راجِع الازدحام).
    • pauseDuration: إجمالي الوقت الذي تمّ قضاؤه في "إيقاف مؤقت" للعمليات المتزامنة (تنبيهات، طلبات XHR متزامنة).
  • تفاصيل مصدر النص البرمجي:
    • sourceURL: اسم مورد النص البرمجي عند توفّره (أو فارغ إذا لم يتم العثور عليه).
    • sourceFunctionName: اسم دالة النص البرمجي حيثما كان متاحًا (أو فارغ إذا لم يتم العثور عليه).
    • sourceCharPosition: موضع الحرف في النص البرمجي عند توفّره (أو -1 في حال عدم العثور عليه).
  • windowAttribution: الحاوية (المستند على المستوى الأعلى أو <iframe>) التي حدث فيها إطار الصورة المتحركة الطويل.
  • window: إشارة إلى نافذة المصدر نفسه

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

مثال على إدخال أداء long-animation-frame

في ما يلي مثال كامل على إدخال أداء long-animation-frame يحتوي على نص برمجي واحد:

{
  "blockingDuration": 0,
  "duration": 60,
  "entryType": "long-animation-frame",
  "firstUIEventTimestamp": 11801.099999999627,
  "name": "long-animation-frame",
  "renderStart": 11858.800000000745,
  "scripts": [
    {
      "duration": 45,
      "entryType": "script",
      "executionStart": 11803.199999999255,
      "forcedStyleAndLayoutDuration": 0,
      "invoker": "DOMWindow.onclick",
      "invokerType": "event-listener",
      "name": "script",
      "pauseDuration": 0,
      "sourceURL": "https://web.dev/js/index-ffde4443.js",
      "sourceFunctionName": "myClickHandler",
      "sourceCharPosition": 17796,
      "startTime": 11803.199999999255,
      "window": [Window object],
      "windowAttribution": "self"
    }
  ],
  "startTime": 11802.400000000373,
  "styleAndLayoutStart": 11858.800000000745
}

كما هو واضح، يقدّم ذلك قدرًا غير مسبوق من البيانات للمواقع الإلكترونية كي تتمكّن من فهم سبب بطء تعديلات العرض.

استخدام Long Animation Frames API في الحقل

على الرغم من أنّ أدوات مثل "أدوات مطوّري البرامج في Chrome" وLighthouse مفيدة لاكتشاف المشاكل وإعادة إنتاجها، إلا أنّها أدوات تجريبية قد لا ترصد جوانب مهمة من تجربة المستخدم لا يمكن توفيرها إلا من خلال البيانات الميدانية.

تم تصميم Long Animation Frames API لاستخدامها في المجال من أجل جمع البيانات السياقية المهمة لتفاعلات المستخدمين التي لا يمكن لواجهة برمجة التطبيقات Long Tasks API جمعها. ويمكن أن يساعدك ذلك في تحديد المشاكل المتعلّقة بالتفاعل وإعادة إنتاجها، والتي لم تكن لتتمكّن من اكتشافها بنفسك.

إتاحة استخدام Long Animation Frames API لميزة رصد المحتوى

يمكنك استخدام الرمز التالي لاختبار ما إذا كانت واجهة برمجة التطبيقات متوافقة:

if (PerformanceObserver.supportedEntryTypes.includes('long-animation-frame')) {
  // Monitor LoAFs
}

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

"مقياس استجابة الصفحة لتفاعلات المستخدم (INP) للصفحة المعروضة" هو مقياس استجابة الصفحة المعروضة الذي يتضمّن تفاعل INP، كما هو موضّح في المخطّط البياني التالي:

أمثلة على إطارات الصور المتحركة الطويلة على صفحة، مع تمييز &quot;الإطارات الطويلة للصور المتحركة&quot; في INP
قد تحتوي الصفحة على العديد من عناصر LoAF، ويكون أحدها مرتبطًا بتفاعل INP.

في بعض الحالات، من الممكن أن يمتدّ حدث INP على إطارَي LoAF، وذلك عادةً إذا حدث التفاعل بعد أن بدأ عرض جزء من الإطار السابق، وبالتالي تتم معالجة معالِج الحدث في الإطار التالي:

أمثلة على إطارات الصور المتحركة الطويلة على صفحة، مع تمييز &quot;الإطارات الطويلة للصور المتحركة&quot; في INP
قد تحتوي الصفحة على العديد من عناصر LoAF، ويكون أحدها مرتبطًا بتفاعل INP.

ومن الممكن أن يشمل أكثر من اثنين من طلبات البحث ذات الصلة في بعض الحالات النادرة.

يتيح لك تسجيل بيانات LoAF المرتبطة بالتفاعل مع INP الحصول على مزيد من المعلومات عن التفاعل مع INP للمساعدة في تشخيصه. ويُعدّ ذلك مفيدًا بشكل خاص لفهم تأخُّر الإدخال: إذ يمكنك الاطّلاع على البرامج النصية الأخرى التي كانت تعمل في ذلك الإطار.

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

لا تتوفّر واجهة برمجة تطبيقات مباشرة لربط إدخال INP بإدخالات LoAF ذات الصلة، ولكن يمكن إجراء ذلك في الرمز البرمجي من خلال مقارنة وقتَي البدء والانتهاء لكل إدخال (راجِع مثال النص البرمجي WhyNp). تتضمّن مكتبة web-vitals جميع مساحات العرض المتداخلة في موقع longAnimationFramesEntries لواجهة تحديد المصدر بالاستناد إلى الإحالات الناجحة (INP) من الإصدار 4.

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

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

الإبلاغ عن المزيد من بيانات الصور المتحركة الطويلة إلى نقطة نهاية إحصاءات

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

لذا، بدلاً من الاطّلاع على بيانات "وقت التحميل في وضع عدم الاتّصال بالإنترنت" (INP LoAF) فقط، ننصحك بالاطّلاع على جميع بيانات "وقت التحميل في وضع عدم الاتّصال بالإنترنت" على مدار عمر الصفحة:

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

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

تشمل بعض الأنماط المقترَحة لتقليل مقدار بيانات إطارات الصور الطويلة للرسوم المتحركة ما يلي:

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

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

مراقبة صور متحركة طويلة مع التفاعلات

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

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

يسجِّل الرمز التالي جميع إدخالات LoAF التي يكون فيها blockingDuration أكبر من 100 ملي ثانية، وذلك عندما يحدث تفاعل خلال اللقطة. تم اختيار 100 هنا لأنّه أقل من الحدّ الأدنى لقيمة INP "الجيدة" التي تبلغ 200 ملي ثانية. يمكنك اختيار قيمة أعلى أو أقل حسب احتياجاتك.

const REPORTING_THRESHOLD_MS = 100;

const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    if (entry.blockingDuration > REPORTING_THRESHOLD_MS &&
      entry.firstUIEventTimestamp > 0
    ) {
      // Example here logs to console, but could also report back to analytics
      console.log(entry);
    }
  }
});
observer.observe({ type: 'long-animation-frame', buffered: true });

راقِب لقطات الصور المتحركة الطويلة التي تتضمن فترات حظر طويلة.

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

يسجِّل الرمز التالي جميع إدخالات LoAF التي تزيد مدة حظرها عن 100 ملي ثانية، وذلك عندما يحدث تفاعل خلال اللقطة. تم اختيار 100 هنا لأنّه أقل من الحدّ الأدنى لقيمة INP "الجيدة" التي تبلغ 200 ملي ثانية، وذلك للمساعدة في تحديد اللقطات التي قد تتضمّن مشاكل محتملة، مع الحدّ من عدد اللقطات الطويلة للرسوم المتحركة التي يتم تسجيلها إلى الحدّ الأدنى. يمكنك اختيار قيمة أعلى أو أقل حسب احتياجاتك.

const REPORTING_THRESHOLD_MS = 100;

const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    if (entry.blockingDuration > REPORTING_THRESHOLD_MS) {
      // Example here logs to console, but could also report back to analytics
      console.log(entry);
    }
  }
});
observer.observe({ type: 'long-animation-frame', buffered: true });

مراقبة إطارات الرسوم المتحركة الطويلة أثناء تحديثات واجهة المستخدم المهمة لتحسين سلاسة الأداء

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

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

const REPORTING_THRESHOLD_MS = 100;

const observer = new PerformanceObserver(list => {
  if (measureImportantUIupdate) {
    for (const entry of list.getEntries()) {
      if (entry.duration > REPORTING_THRESHOLD_MS) {
        // Example here logs to console, but could also report back to analytics
        console.log(entry);
      }
    }
  }
});
observer.observe({ type: 'long-animation-frame', buffered: true });

async function doUIUpdatesWithMeasurements() {
  measureImportantUIupdate = true;
  await doUIUpdates();
  measureImportantUIupdate = false;
}

مراقبة أسوأ صور متحركة تستغرق وقتًا طويلاً

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

MAX_LOAFS_TO_CONSIDER = 10;
let longestBlockingLoAFs = [];

const observer = new PerformanceObserver(list => {
  longestBlockingLoAFs = longestBlockingLoAFs.concat(list.getEntries()).sort(
    (a, b) => b.blockingDuration - a.blockingDuration
  ).slice(0, MAX_LOAFS_TO_CONSIDER);
});
observer.observe({ type: 'long-animation-frame', buffered: true });

يمكن أيضًا دمج هذه الاستراتيجيات، وذلك من خلال الاطّلاع فقط على أسوأ 10 طلبات بحث ذات وقت استجابة طويل، والتي تتضمن تفاعلات تزيد مدتها عن 100 ملي ثانية.

في الوقت المناسب (يُفضَّل عند حدوث الحدث visibilitychange)، تُرسِل الإشارة مرة أخرى إلى "إحصاءات Google". للاختبار على الجهاز، يمكنك استخدام console.table بشكل دوري:

console.table(longestBlockingLoAFs);

تحديد الأنماط الشائعة في إطارات الصور المتحركة الطويلة

ويمكنك اتّباع استراتيجية بديلة تتمثل في الاطّلاع على النصوص البرمجية الشائعة التي تظهر بشكل أكبر في إدخالات إطارات الرسوم المتحركة الطويلة. يمكن تسجيل البيانات على مستوى النص البرمجي وموضع الحرف لتحديد المخالفين المتكررين.

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

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

const observer = new PerformanceObserver(list => {
  const allScripts = list.getEntries().flatMap(entry => entry.scripts);
  const scriptSource = [...new Set(allScripts.map(script => script.sourceURL))];
  const scriptsBySource= scriptSource.map(sourceURL => ([sourceURL,
      allScripts.filter(script => script.sourceURL === sourceURL)
  ]));
  const processedScripts = scriptsBySource.map(([sourceURL, scripts]) => ({
    sourceURL,
    count: scripts.length,
    totalDuration: scripts.reduce((subtotal, script) => subtotal + script.duration, 0)
  }));
  processedScripts.sort((a, b) => b.totalDuration - a.totalDuration);
  // Example here logs to console, but could also report back to analytics
  console.table(processedScripts);
});

observer.observe({type: 'long-animation-frame', buffered: true});

في ما يلي مثال على هذا الناتج:

(index) sourceURL count totalDuration
0 'https://example.consent.com/consent.js' 1 840
1 'https://example.com/js/analytics.js' 7 628
2 'https://example.chatapp.com/web-chat.js' 1 5

استخدام Long Animation Frames API في الأدوات

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

عرض بيانات صور متحركة تستغرق عرضها وقتًا طويلاً في "أدوات مطوّري البرامج"

يمكنك عرض لقطات متحركة طويلة في أدوات مطوّري البرامج باستخدام واجهة برمجة التطبيقات performance.measure()، والتي يتم عرضها بعد ذلك في مسار توقيتات المستخدِم في أدوات مطوّري البرامج في عمليات تتبُّع الأداء لتحديد المواضع التي يجب التركيز فيها لتحسين الأداء. باستخدام DevTools Extensibility API، يمكن عرض هذه العناصر في مسارها الخاص:

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    performance.measure('LoAF', {
      start: entry.startTime,
      end: entry.startTime + entry.duration,
      detail: {
        devtools: {
          dataType: "track-entry",
          track: "Long animation frames",
          trackGroup: "Performance Timeline",
          color: "tertiary-dark",
          tooltipText: 'LoAF'
        }
      }
    });
  }
});

observer.observe({ type: 'long-animation-frame', buffered: true });
تتبُّع لوحة الأداء في DevTools باستخدام مسار مخصّص يعرض بيانات إطارات الصور المتحركة الطويلة التي يمكن مقارنتها بالرسم البياني الرئيسي للأداء
عرض بيانات إطارات الصور الطويلة للرسوم المتحركة في "أدوات مطوّري البرامج"

على المدى الطويل، من المرجّح أن يتم دمج إطارات الرسوم المتحركة الطويلة في "أدوات مطوّري البرامج" نفسها، ولكنّ مقتطف الرمز البرمجي السابق يسمح بعرضها هناك في الوقت الحالي.

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

استخدام بيانات إطارات الرسوم المتحركة الطويلة في أدوات المطوّرين الأخرى

أظهرت إضافة "مؤشرات أداء الويب" القيمة في معلومات تصحيح الأخطاء في ملخّص التسجيل لتشخيص مشاكل الأداء.

ويعرِض الآن أيضًا بيانات إطارات الرسوم المتحركة الطويلة لكلّ مكالمة واردة من مقياس مدى استجابة الصفحة لتفاعلات المستخدم (INP) وكلّ تفاعل:

تسجيل وحدة تحكّم إضافة &quot;مؤشرات أداء الويب&quot;
تعرض سجلّات وحدة تحكّم "إضافة مؤشرات أداء الويب" بيانات LoAF.

استخدام بيانات إطارات الرسوم المتحركة الطويلة في أدوات الاختبار الآلي

وبالمثل، يمكن لأدوات الاختبار المبرمَجة في مسارات التكامل المستمر/النشر الدائم عرض تفاصيل عن المشاكل المحتملة في الأداء من خلال قياس إطارات الصور الطويلة للرسوم المتحركة أثناء تشغيل مجموعات اختبارات مختلفة.

الأسئلة الشائعة

في ما يلي بعض الأسئلة الشائعة حول واجهة برمجة التطبيقات هذه:

لماذا لا يتم ببساطة توسيع نطاق Long Tasks API أو تكرار استخدامها؟

هذه طريقة بديلة لإعداد تقارير عن قياس مشابه، ولكن مختلف في النهاية، للمشاكل المحتمَلة في الاستجابة. من المهم ضمان استمرار عمل المواقع الإلكترونية التي تعتمد على Long Tasks API الحالية لتجنُّب إيقاف حالات الاستخدام الحالية.

على الرغم من أنّ Long Tasks API قد تستفيد من بعض ميزات LoAF (مثل نموذج تحديد مصدر أفضل)، نعتقد أنّ التركيز على اللقطات بدلاً من المهام يقدّم العديد من المزايا التي تجعل هذه الواجهة مختلفة بشكل أساسي عن Long Tasks API الحالية.

Why do I not have script entries?

قد يشير ذلك إلى أنّ إطار الرسوم المتحركة الطويل لم يكن بسبب JavaScript، بل بسبب عمل كبير في المعالجة.

يمكن أن يحدث ذلك أيضًا عندما يكون إطار الصورة المتحرّكة الطويل ناتجًا عن JavaScript ولكن لا يمكن تقديم مصدر النص البرمجي لأسباب خصوصية مختلفة كما هو موضّح سابقًا (أهمّها أنّ JavaScript ليس ملكًا للصفحة).

لماذا تتوفّر لديّ إدخالات نصوص برمجية ولكن لا تتوفّر معلومات مصدر أو تتوفّر معلومات محدودة؟

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

ستقتصر معلومات النصوص البرمجية أيضًا على sourceURL فقط (باستثناء أي عمليات إعادة توجيه) لنصوص no-cors cross-origin البرمجية، مع سلسلة فارغة للعنصر sourceFunctionName و-1 للعنصر sourceCharPosition. يمكن حلّ هذه المشكلة من خلال جلب النصوص البرمجية هذه باستخدام سياسة مشاركة الموارد المتعددة المصادر (CORS) عن طريق إضافة crossOrigin = "anonymous" إلى طلب <script>.

على سبيل المثال، النص البرمجي التلقائي لخدمة "مدير علامات Google" لإضافته إلى الصفحة:

<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');</script>
<!-- End Google Tag Manager -->

يمكن تحسينه لإضافة j.crossOrigin = "anonymous" للسماح بتقديم تفاصيل تحديد المصدر الكاملة لخدمة "إحصاءات Google‏ 4".

هل ستحل هذه الواجهة محل Long Tasks API؟

على الرغم من أنّنا نعتقد أنّ Long Animation Frames API هي واجهة برمجة تطبيقات أفضل وأكمل لقياس المهام الطويلة، لا تتوفّر حاليًا أيّ خطط لإيقاف Long Tasks API نهائيًا.

نريد معرفة ملاحظاتك

يمكن تقديم الملاحظات في قائمة مشاكل GitHub، أو يمكن الإبلاغ عن الأخطاء في تنفيذ واجهة برمجة التطبيقات في Chrome في نظام تتبُّع المشاكل في Chrome.

الخاتمة

‫Long Animation Frames API هي واجهة برمجة تطبيقات جديدة ومثيرة للاهتمام توفّر العديد من المزايا المحتملة مقارنةً بواجهة برمجة التطبيقات السابقة Long Tasks API.

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

يتجاوز نطاق Long Animation Frames API مقياس INP، ويمكن أن يساعد في تحديد أسباب أخرى للتحديثات البطيئة التي يمكن أن تؤثّر في سلاسة تجربة المستخدم على الموقع الإلكتروني بشكل عام.

الشكر والتقدير

الصورة المصغّرة لأحد أعمال Henry Be على Unsplash.