تعرَّف على كيفية العثور على التفاعلات البطيئة في بيانات موقعك الإلكتروني الميدانية لتحديد فرص تحسين مقياس "مدة عرض الاستجابة لتفاعل المستخدم".
بيانات الحقل هي بيانات توضّح لك تجربة المستخدمين الفعليين على موقعك الإلكتروني. فهي تكشف عن المشاكل التي لا يمكنك العثور عليها في بيانات المختبر وحدها. في ما يتعلق بمقياس مدى استجابة الصفحة لتفاعلات المستخدم (INP)، تكون بيانات الحقل ضرورية لتحديد التفاعلات البطيئة، كما تقدّم إشارات مهمة لمساعدتك في إصلاحها.
في هذا الدليل، ستتعرّف على كيفية تقييم مقياس INP لموقعك الإلكتروني بسرعة باستخدام بيانات الاستخدام الفعلي من تقرير تجربة مستخدمي Chrome (CrUX) لمعرفة ما إذا كان موقعك الإلكتروني يواجه مشاكل في مقياس INP. بعد ذلك، ستتعرّف على كيفية استخدام إصدار تحديد المصدر من مكتبة JavaScript الخاصة بمقاييس Web Vitals، والإحصاءات الجديدة التي يقدّمها Long Animation Frames API (LoAF)، وذلك لجمع بيانات ميدانية وتفسيرها بشأن التفاعلات البطيئة على موقعك الإلكتروني.
ابدأ باستخدام CrUX لتقييم INP لموقعك الإلكتروني
إذا كنت لا تجمع بيانات فعلية من مستخدمي موقعك الإلكتروني، قد تكون CrUX نقطة بداية جيدة. يجمع CrUX بيانات الاستخدام الفعلي من مستخدمي Chrome الفعليين الذين وافقوا على إرسال بيانات القياس عن بُعد.
تظهر بيانات CrUX في عدد من الأماكن المختلفة، ويعتمد ذلك على نطاق المعلومات التي تبحث عنها. يمكن أن يوفّر CrUX بيانات حول مقياس "مدى استجابة الصفحة لتفاعلات المستخدم" (INP) ومؤشرات أداء الويب الأساسية الأخرى لما يلي:
- الصفحات الفردية والمصادر بأكملها باستخدام إحصاءات PageSpeed
- أنواع الصفحات على سبيل المثال، تتضمّن العديد من مواقع التجارة الإلكترونية نوعَي "صفحة تفاصيل المنتج" و"صفحة قائمة المنتجات". يمكنك الحصول على بيانات CrUX لأنواع الصفحات الفريدة في Search Console.
كنقطة بداية، يمكنك إدخال عنوان URL لموقعك الإلكتروني في "إحصاءات PageSpeed". بعد إدخال عنوان URL، سيتم عرض بيانات الحقل الخاصة به، إذا كانت متاحة، لعدة مقاييس، بما في ذلك مقياس INP. يمكنك أيضًا استخدام أزرار التبديل للتحقّق من قيم INP لسمات الأجهزة الجوّالة وأجهزة الكمبيوتر.

هذه البيانات مفيدة لأنّها تخبرك ما إذا كانت لديك مشكلة. في المقابل، لا يمكن لأداة CrUX أن تخبرك بسبب حدوث المشاكل. تتوفّر العديد من حلول مراقبة تجربة المستخدم الحقيقية (RUM) التي ستساعدك في جمع بيانات الحقول الخاصة بك من مستخدمي موقعك الإلكتروني لمساعدتك في الإجابة عن هذا السؤال، وأحد الخيارات هو جمع بيانات الحقول بنفسك باستخدام مكتبة JavaScript الخاصة بمقاييس Web Vitals.
جمع بيانات الحقول باستخدام مكتبة JavaScript الخاصة بـ web-vitals
مكتبة JavaScript web-vitals
هي نص برمجي يمكنك تحميله على موقعك الإلكتروني لجمع بيانات الحقول من مستخدمي موقعك الإلكتروني. يمكنك استخدامها لتسجيل عدد من المقاييس، بما في ذلك مقياس INP في المتصفحات التي تتوافق معه.
يمكن استخدام الإصدار العادي من مكتبة 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. وهنا يأتي دور إصدار الإحالة لمكتبة web-vitals.
تحقيق نتائج أفضل من خلال ميزة تحديد المصدر في مكتبة web-vitals
تعرض نسخة تحديد المصدر من مكتبة 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
});

بالإضافة إلى مقياس INP الخاص بالصفحة، يوفّر إصدار الإحالة المستندة إلى المصدر الكثير من البيانات التي يمكنك استخدامها للمساعدة في فهم أسباب بطء التفاعلات، بما في ذلك الجزء الذي يجب التركيز عليه من التفاعل. يمكن أن يساعدك ذلك في الإجابة عن أسئلة مهمة، مثل:
- "هل تفاعل المستخدم مع الصفحة أثناء تحميلها؟"
- "هل استغرقت معالجات أحداث التفاعل وقتًا طويلاً؟"
- "هل تم تأخير بدء تشغيل رمز معالج حدث التفاعل؟ وإذا كان الأمر كذلك، ما هي العمليات الأخرى التي كانت تحدث على سلسلة التعليمات الرئيسية في ذلك الوقت؟"
- "هل أدّى التفاعل إلى تنفيذ الكثير من عمليات العرض التي أخرّت عرض الإطار التالي؟"
يعرض الجدول التالي بعض بيانات تحديد المصدر الأساسية التي يمكنك الحصول عليها من المكتبة والتي يمكن أن تساعدك في معرفة بعض الأسباب الرئيسية لبطء التفاعلات على موقعك الإلكتروني:
مفتاح العنصر attribution
|
البيانات |
---|---|
interactionTarget
|
محدّد CSS يشير إلى العنصر الذي أدّى إلى ظهور قيمة INP للصفحة، مثل button#save .
|
interactionType
|
نوع التفاعل، سواء كان من النقرات أو النقر أو إدخالات لوحة المفاتيح |
inputDelay *
|
مهلة الاستجابة للإدخال للتفاعل |
processingDuration *
|
الوقت المستغرَق منذ بدء تشغيل أول معالج للأحداث استجابةً لتفاعل المستخدم إلى حين انتهاء جميع عمليات معالجة الأحداث |
presentationDelay *
|
مهلة العرض للتفاعل، والتي تبدأ من وقت انتهاء معالجات الأحداث إلى وقت رسم الإطار التالي |
longAnimationFrameEntries *
|
الإدخالات من سجلّ "النشاط على التطبيقات والمواقع الإلكترونية" المرتبطة بالتفاعل يُرجى الاطّلاع على ما يلي للحصول على معلومات إضافية. |
بدءًا من الإصدار 4 من مكتبة web-vitals، يمكنك الحصول على إحصاءات أكثر تفصيلاً عن التفاعلات التي تتضمّن مشاكل من خلال البيانات التي توفّرها مع تفاصيل مراحل INP (وقت تأخير الإدخال ومدة المعالجة ووقت تأخير العرض) وLong Animation Frames API (LoAF).
واجهة برمجة التطبيقات Long Animation Frames API (LoAF)
إنّ تصحيح أخطاء التفاعلات باستخدام بيانات الحقول مهمة صعبة. باستخدام بيانات LoAF، أصبح من الممكن الآن الحصول على إحصاءات أفضل حول أسباب بطء التفاعلات، لأنّ LoAF يعرض عددًا من التوقيتات التفصيلية والبيانات الأخرى التي يمكنك استخدامها لتحديد الأسباب الدقيقة، والأهم من ذلك، تحديد مصدر المشكلة في رمز موقعك الإلكتروني.
يعرض إصدار تحديد المصدر من مكتبة web-vitals مصفوفة من إدخالات LoAF ضمن المفتاح longAnimationFrameEntries
للعنصر attribution
. يعرض الجدول التالي بعض البيانات الأساسية التي يمكنك العثور عليها في كل إدخال في سجلّ النشاط على التطبيق أو الموقع الإلكتروني:
مفتاح عنصر إدخال LoAF | البيانات |
---|---|
duration
|
تمثّل هذه السمة مدة عرض الصورة المتحركة التي يستغرق عرضها وقتًا طويلاً، وذلك حتى اكتمال التنسيق، ولكن باستثناء الرسم والتركيب. |
blockingDuration
|
إجمالي الوقت الذي لم يتمكّن المتصفّح خلاله من الاستجابة بسرعة بسبب المهام الطويلة. يمكن أن يتضمّن وقت الحظر هذا مهامًا طويلة تشغّل JavaScript، بالإضافة إلى أي مهمة عرض طويلة لاحقة في الإطار. |
firstUIEventTimestamp
|
الطابع الزمني لوقت وضع الحدث في قائمة الانتظار أثناء الإطار مفيدة لمعرفة بداية تأخير الإدخال لأحد التفاعلات. |
startTime
|
الطابع الزمني لبداية الإطار |
renderStart
|
الوقت الذي بدأ فيه عرض إطار الفيديو ويشمل ذلك أي استدعاءات requestAnimationFrame (واستدعاءات ResizeObserver إذا كان ذلك منطبقًا)، ولكن من المحتمل أن يكون ذلك قبل بدء أي عمل متعلق بالتصميم أو التنسيق.
|
styleAndLayoutStart
|
عندما يتم العمل على النمط أو التنسيق في الإطار يمكن أن يكون ذلك مفيدًا في تحديد مدة العمل على الأسلوب/التصميم عند احتساب الطوابع الزمنية الأخرى المتاحة. |
scripts
|
مصفوفة من العناصر التي تحتوي على معلومات تحديد مصدر النصوص البرمجية التي تساهم في مقياس INP للصفحة. |

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 لتحديد السبب الدقيق وراء تفاعل يتضمّن قيمًا عالية لمدة المعالجة، بما في ذلك:
- العنصر وأداة معالجة الحدث المسجّلة
- ملف البرنامج النصي، وموضع الحرف فيه، الذي يحتوي على رمز معالج الأحداث الذي يستغرق وقتًا طويلاً
- اسم الدالة
هذا النوع من البيانات لا يُقدّر بثمن. لم يعُد عليك بذل الجهد للعثور على التفاعل المسؤول عن قيم مدة المعالجة العالية أو معالج الأحداث المسؤول عن ذلك. بالإضافة إلى ذلك، بما أنّ النصوص البرمجية التابعة لجهات خارجية يمكنها غالبًا تسجيل معالجات الأحداث الخاصة بها، يمكنك تحديد ما إذا كان الرمز البرمجي الخاص بك هو المسؤول أم لا. بالنسبة إلى الرمز الذي يمكنك التحكّم فيه، عليك البحث عن طرق تحسين المهام الطويلة.
تأخيرات طويلة في عملية الإدخال
على الرغم من أنّ معالجات الأحداث التي تستغرق وقتًا طويلاً شائعة، هناك أجزاء أخرى من التفاعل يجب أخذها في الاعتبار. يحدث جزء واحد قبل مدة المعالجة، ويُعرف باسم تأخير الإدخال. هذا هو الوقت المستغرَق منذ أن يبدأ المستخدم التفاعل إلى أن تبدأ عمليات معاودة الاتصال بمعالج الأحداث في التنفيذ، ويحدث ذلك عندما تكون سلسلة التعليمات الرئيسية تعالج مهمة أخرى. يمكن أن يخبرك إصدار تحديد المصدر في مكتبة web-vitals بمدة تأخُّر الاستجابة للتفاعل:
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.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 بمدة عمل الأسلوب والتصميم لإطار معيّن، ولكن سيخبرك بموعد بدء هذا العمل. باستخدام هذا الطابع الزمني الأوّلي، يمكنك استخدام بيانات أخرى من "إطار العمل أثناء التنفيذ" لحساب مدة دقيقة لهذا العمل من خلال تحديد وقت انتهاء الإطار وطرح الطابع الزمني الأوّلي لعمل التصميم والتنسيق من ذلك الوقت.
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
، تأكَّد من أنّ العمل الذي تجريه في عمليات الاسترجاع هذه يقتصر على تنفيذ العمل الذي يؤدي إلى تعديل فعلي في واجهة المستخدم. أي عمل آخر لا يؤثر في نموذج المستند أو يعدّل الأنماط سيؤدي إلى تأخير عرض الإطار التالي بلا داعٍ، لذا عليك توخّي الحذر.
الخاتمة
تُعدّ بيانات الحقل أفضل مصدر للمعلومات يمكنك الاستناد إليه عند فهم التفاعلات التي تسبّب مشاكل للمستخدمين الفعليين في الحقل. من خلال الاعتماد على أدوات جمع البيانات الميدانية، مثل مكتبة JavaScript الخاصة بمقاييس Web Vitals (أو أحد موفّري مراقبة تجربة المستخدم الحقيقية)، يمكنك أن تكون أكثر ثقة بشأن التفاعلات الأكثر إشكالية، ثم الانتقال إلى إعادة إنتاج التفاعلات الإشكالية في المختبر ثم البدء في إصلاحها.
الصورة الرئيسية من Unsplash، من تصوير فيديريكو ريسبيني.