نظرة عميقة على واجهات برمجة تطبيقات أداء الويب، من قياسات التوقيت التقليدية إلى المقاييس الحديثة التي تركز على المستخدم مثل مؤشرات أداء الويب الأساسية، وكيفية ربطها للحصول على رؤية شاملة للأداء.
ما وراء الساعة: ربط واجهات برمجة تطبيقات أداء الويب بتجربة المستخدم الحقيقية
في الاقتصاد الرقمي، السرعة ليست مجرد ميزة؛ إنها أساس تجربة المستخدم. يمكن أن يؤدي موقع الويب البطيء إلى إحباط المستخدمين، وارتفاع معدلات الارتداد، وتأثير مباشر على الإيرادات. لسنوات، اعتمد المطورون على مقاييس التوقيت مثل window.onload
لقياس الأداء. ولكن هل يعني وقت التحميل السريع حقًا مستخدمًا سعيدًا؟ الجواب غالبًا لا.
يمكن أن تنتهي الصفحة من تحميل جميع مواردها التقنية في أقل من ثانية، ومع ذلك تبدو بطيئة وغير قابلة للاستخدام لشخص حقيقي يحاول التفاعل معها. يسلط هذا الانفصال الضوء على تطور حاسم في تطوير الويب: التحول من قياس التوقيتات التقنية إلى تحديد كمية التجربة البشرية. أداء الويب الحديث هو قصة من منظورين: البيانات الدقيقة منخفضة المستوى التي توفرها واجهات برمجة تطبيقات أداء الويب، والمقاييس عالية المستوى التي تركز على المستخدم مثل مؤشرات أداء الويب الأساسية من Google.
سيسد هذا الدليل الشامل تلك الفجوة. سنستكشف مجموعة واجهات برمجة تطبيقات أداء الويب القوية التي تعمل كأدوات تشخيصية لنا. بعد ذلك، سنتعمق في مقاييس تجربة المستخدم الحديثة التي تخبرنا كيف *يبدو* الأداء. والأهم من ذلك، سنقوم بربط النقاط، لنوضح لك كيفية استخدام بيانات التوقيت منخفضة المستوى لتشخيص وإصلاح الأسباب الجذرية لتجربة المستخدم السيئة لجمهورك العالمي.
الأساس: فهم واجهات برمجة تطبيقات أداء الويب
واجهات برمجة تطبيقات أداء الويب هي مجموعة من الواجهات الموحدة للمتصفح تمنح المطورين إمكانية الوصول إلى بيانات توقيت عالية الدقة والتفصيل تتعلق بتنقل وعرض صفحة الويب. إنها حجر الأساس لقياس الأداء، مما يسمح لنا بتجاوز ساعات التوقيت البسيطة وفهم الرقصة المعقدة لطلبات الشبكة، والتحليل، والعرض.
واجهة برمجة تطبيقات توقيت التنقل (Navigation Timing API): رحلة الصفحة
توفر واجهة برمجة تطبيقات توقيت التنقل تفصيلاً دقيقاً للوقت الذي يستغرقه تحميل المستند الرئيسي. إنها تلتقط المعالم الرئيسية من لحظة بدء المستخدم للتنقل (مثل النقر على رابط) إلى لحظة تحميل الصفحة بالكامل. هذه هي نظرتنا الأولى والأكثر أساسية في عملية تحميل الصفحة.
يمكنك الوصول إلى هذه البيانات باستدعاء JavaScript بسيط:
const navigationEntry = performance.getEntriesByType('navigation')[0];
console.log(navigationEntry.toJSON());
يعيد هذا كائنًا مليئًا بالطوابع الزمنية. تتضمن بعض الخصائص الرئيسية ما يلي:
- fetchStart: عندما يبدأ المتصفح في جلب المستند.
- responseStart: عندما يتلقى المتصفح أول بايت من الاستجابة من الخادم. غالبًا ما يشار إلى الوقت بين
fetchStart
وresponseStart
باسم زمن استلام أول بايت (TTFB). - domContentLoadedEventEnd: عندما يتم تحميل وتحليل مستند HTML الأولي بالكامل، دون انتظار انتهاء تحميل أوراق الأنماط والصور والإطارات الفرعية.
- loadEventEnd: عندما يتم تحميل جميع موارد الصفحة (بما في ذلك الصور، CSS، إلخ) بالكامل.
لفترة طويلة، كان loadEventEnd
هو المعيار الذهبي. ومع ذلك، فإن قصوره شديد: فهو لا يخبرنا شيئًا عن متى *يرى* المستخدم محتوى ذا معنى أو متى يمكنه *التفاعل* مع الصفحة. إنه معلم تقني، وليس معلمًا بشريًا.
واجهة برمجة تطبيقات توقيت الموارد (Resource Timing API): تفكيك المكونات
نادرًا ما تكون صفحة الويب ملفًا واحدًا. إنها تجميع لملفات HTML و CSS و JavaScript والصور والخطوط واستدعاءات API. تتيح لك واجهة برمجة تطبيقات توقيت الموارد فحص توقيت الشبكة لكل من هذه الموارد الفردية.
هذا قوي بشكل لا يصدق لتحديد الاختناقات. هل هناك صورة بطل كبيرة غير محسّنة من شبكة توصيل المحتوى (CDN) في قارة أخرى تبطئ العرض الأولي؟ هل يقوم سكربت تحليلات من طرف ثالث بحظر الخيط الرئيسي؟ تساعدك واجهة توقيت الموارد في الإجابة على هذه الأسئلة.
يمكنك الحصول على قائمة بجميع الموارد على هذا النحو:
const resourceEntries = performance.getEntriesByType('resource');
resourceEntries.forEach(resource => {
if (resource.duration > 200) { // Find resources that took longer than 200ms
console.log(`Slow resource: ${resource.name}, Duration: ${resource.duration}ms`);
}
});
تتضمن الخصائص الرئيسية name
(عنوان URL للمورد)، و initiatorType
(ما الذي تسبب في تحميل المورد، على سبيل المثال، 'img'، 'script')، و duration
(إجمالي الوقت المستغرق لجلبه).
واجهة برمجة تطبيقات توقيت المستخدم (User Timing API): قياس منطق تطبيقك
أحيانًا، لا يكمن عنق الزجاجة في الأداء في تحميل الأصول بل في الكود البرمجي من جانب العميل نفسه. كم من الوقت يستغرقه تطبيق الصفحة الواحدة (SPA) لعرض مكون معقد بعد استلام البيانات من واجهة برمجة التطبيقات؟ تتيح لك واجهة برمجة تطبيقات توقيت المستخدم إنشاء قياسات مخصصة خاصة بالتطبيق.
تعمل بطريقتين رئيسيتين:
- performance.mark(name): تنشئ طابعًا زمنيًا مسمى في مخزن الأداء المؤقت.
- performance.measure(name, startMark, endMark): تحسب المدة بين علامتين وتنشئ قياسًا مسمى.
مثال: قياس وقت عرض مكون قائمة المنتجات.
// عندما تبدأ في جلب البيانات
performance.mark('product-list-fetch-start');
fetch('/api/products')
.then(response => response.json())
.then(data => {
// بعد الجلب، قبل العرض
performance.mark('product-list-render-start');
renderProductList(data);
// مباشرة بعد اكتمال العرض
performance.mark('product-list-render-end');
// إنشاء قياس
performance.measure(
'Product List Render Time',
'product-list-render-start',
'product-list-render-end'
);
});
يمنحك هذا تحكمًا دقيقًا لقياس أجزاء تطبيقك الأكثر أهمية لسير عمل المستخدم.
مراقب الأداء (PerformanceObserver): النهج الحديث والفعال
إن الاستعلام المستمر لـ `performance.getEntriesByType()` غير فعال. توفر واجهة `PerformanceObserver` API طريقة أفضل بكثير للاستماع إلى إدخالات الأداء. أنت تشترك في أنواع إدخالات محددة، ويقوم المتصفح بإعلام دالة رد الاتصال الخاصة بك بشكل غير متزامن عند تسجيلها. هذه هي الطريقة الموصى بها لجمع بيانات الأداء دون إضافة عبء على تطبيقك.
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(`Entry Type: ${entry.entryType}, Name: ${entry.name}`);
}
});
observer.observe({ entryTypes: ['resource', 'navigation', 'mark', 'measure'] });
هذا المراقب هو المفتاح لجمع ليس فقط المقاييس التقليدية المذكورة أعلاه ولكن أيضًا المقاييس الحديثة التي تركز على المستخدم والتي سنناقشها بعد ذلك.
التحول نحو التركيز على المستخدم: مؤشرات أداء الويب الأساسية
معرفة أن الصفحة تم تحميلها في ثانيتين أمر مفيد، لكنه لا يجيب على الأسئلة الحاسمة: هل كان المستخدم يحدق في شاشة فارغة خلال هاتين الثانيتين؟ هل كان بإمكانه التفاعل مع الصفحة، أم كانت متجمدة؟ هل قفز المحتوى بشكل غير متوقع أثناء محاولته القراءة؟
لمعالجة هذا الأمر، قدمت Google مؤشرات أداء الويب الأساسية (CWV)، وهي مجموعة من المقاييس المصممة لقياس تجربة المستخدم الواقعية للصفحة عبر ثلاثة أبعاد رئيسية: التحميل، والتفاعلية، والاستقرار البصري.
سرعة عرض أكبر جزء من المحتوى (LCP): قياس التحميل المدرك
يقيس LCP زمن عرض أكبر صورة أو كتلة نصية مرئية داخل إطار العرض. إنه وكيل ممتاز للوقت الذي يشعر فيه المستخدم بأن المحتوى الرئيسي للصفحة قد تم تحميله. يجيب مباشرة على سؤال المستخدم: "هل هذه الصفحة مفيدة بعد؟"
- جيد: أقل من 2.5 ثانية
- بحاجة إلى تحسين: بين 2.5 ثانية و 4.0 ثوانٍ
- ضعيف: أكثر من 4.0 ثوانٍ
على عكس `loadEventEnd`، يركز LCP على ما يراه المستخدم أولاً، مما يجعله انعكاسًا أكثر دقة لسرعة التحميل المدركة.
مدى استجابة الصفحة للتفاعلات (INP): قياس الاستجابة
مقياس INP هو خليفة مقياس مهلة الاستجابة لأول إدخال (FID) وأصبح مؤشرًا أساسيًا رسميًا لأداء الويب في مارس 2024. بينما كان FID يقيس فقط تأخير التفاعل *الأول*، يقيس INP زمن انتقال *جميع* تفاعلات المستخدم (النقرات، اللمسات، ضغطات المفاتيح) طوال دورة حياة الصفحة. يبلغ عن أطول تفاعل، مما يحدد بفعالية أسوأ حالة استجابة يواجهها المستخدم.
يقيس INP الوقت الكامل من إدخال المستخدم حتى يتم رسم الإطار التالي، مما يعكس التغذية الراجعة المرئية. يجيب على سؤال المستخدم: "عندما أنقر على هذا الزر، هل تستجيب الصفحة بسرعة؟"
- جيد: أقل من 200 ميلي ثانية
- بحاجة إلى تحسين: بين 200 ميلي ثانية و 500 ميلي ثانية
- ضعيف: أكثر من 500 ميلي ثانية
عادة ما يكون سبب ارتفاع INP هو انشغال الخيط الرئيسي، حيث تمنع مهام JavaScript طويلة التشغيل المتصفح من الاستجابة لإدخال المستخدم.
متغيّرات التصميم التراكمية (CLS): قياس الاستقرار البصري
يقيس CLS الاستقرار البصري للصفحة. إنه يحدد كمية المحتوى الذي يتحرك بشكل غير متوقع على الشاشة أثناء عملية التحميل. درجة CLS المرتفعة هي مصدر شائع لإحباط المستخدم، كما هو الحال عندما تحاول النقر فوق زر، ولكن يتم تحميل إعلان فوقه، مما يدفع الزر لأسفل ويتسبب في نقرك على الإعلان بدلاً من ذلك.
يجيب CLS على سؤال المستخدم: "هل يمكنني استخدام هذه الصفحة دون أن تقفز العناصر في كل مكان؟"
- جيد: أقل من 0.1
- بحاجة إلى تحسين: بين 0.1 و 0.25
- ضعيف: أكثر من 0.25
تشمل الأسباب الشائعة لارتفاع CLS الصور أو إطارات iframe بدون أبعاد، أو تحميل خطوط الويب في وقت متأخر، أو إدخال المحتوى ديناميكيًا في الصفحة دون حجز مساحة له.
سد الفجوة: استخدام واجهات برمجة التطبيقات لتشخيص تجربة المستخدم السيئة
هنا يجتمع كل شيء. تخبرنا مؤشرات أداء الويب الأساسية *بما* اختبره المستخدم (على سبيل المثال، LCP بطيء). وتخبرنا واجهات برمجة تطبيقات أداء الويب *لماذا* حدث ذلك. من خلال الجمع بينهما، نتحول من مجرد مراقبة الأداء إلى تشخيصه وإصلاحه بفعالية.
تشخيص LCP البطيء
تخيل أن أداة مراقبة المستخدم الحقيقي (RUM) الخاصة بك تبلغ عن LCP ضعيف يبلغ 4.5 ثانية للمستخدمين في منطقة معينة. كيف تصلحه؟ تحتاج إلى تقسيم وقت LCP إلى أجزائه المكونة.
- زمن استلام أول بايت (TTFB): هل الخادم بطيء في الاستجابة؟ استخدم واجهة برمجة تطبيقات توقيت التنقل. المدة `responseStart - requestStart` تمنحك TTFB دقيقًا. إذا كان هذا مرتفعًا، فالمشكلة تكمن في الواجهة الخلفية أو تكوين الخادم أو قاعدة البيانات، وليس الواجهة الأمامية.
- تأخير ووقت تحميل المورد: هل عنصر LCP نفسه بطيء التحميل؟ أولاً، حدد عنصر LCP (على سبيل المثال، صورة البطل). يمكنك استخدام `PerformanceObserver` لـ `'largest-contentful-paint'` للحصول على العنصر نفسه. بعد ذلك، استخدم واجهة برمجة تطبيقات توقيت الموارد للعثور على الإدخال الخاص بعنوان URL لهذا العنصر. حلل جدوله الزمني: هل كان هناك `connectStart` إلى `connectEnd` طويل (شبكة بطيئة)؟ هل كان `responseStart` إلى `responseEnd` طويلًا (حجم ملف ضخم)؟ هل تأخر `fetchStart` الخاص به لأنه تم حظره بواسطة موارد أخرى تحظر العرض مثل CSS أو JavaScript؟
- تأخير عرض العنصر: هذا هو الوقت بعد انتهاء تحميل المورد حتى يتم رسمه فعليًا على الشاشة. يمكن أن يكون سبب ذلك انشغال الخيط الرئيسي بمهام أخرى، مثل تنفيذ حزمة JavaScript كبيرة.
باستخدام توقيت التنقل والموارد، يمكنك تحديد ما إذا كان LCP البطيء ناتجًا عن خادم بطيء، أو سكربت يحظر العرض، أو صورة ضخمة غير محسّنة.
التحقيق في INP الضعيف
يشتكي المستخدمون من أن النقر على زر "إضافة إلى السلة" يبدو بطيئًا. مقياس INP الخاص بك في النطاق "الضعيف". هذه دائمًا مشكلة في الخيط الرئيسي.
- تحديد المهام الطويلة: واجهة برمجة تطبيقات المهام الطويلة (Long Tasks API) هي أداتك الأساسية هنا. إنها تبلغ عن أي مهمة على الخيط الرئيسي تستغرق أكثر من 50 مللي ثانية، حيث أن أي شيء أطول يخاطر بتأخير ملحوظ للمستخدم. قم بإعداد `PerformanceObserver` للاستماع إلى إدخالات `'longtask'`.
- الربط بإجراءات المستخدم: المهمة الطويلة ليست مشكلة إلا إذا حدثت عندما يحاول المستخدم التفاعل. يمكنك ربط `startTime` لحدث INP (الذي تتم ملاحظته عبر `PerformanceObserver` على نوع `'event'`) بتوقيتات أي مهام طويلة حدثت في نفس الوقت تقريبًا. هذا يخبرك بالضبط أي دالة JavaScript حظرت تفاعل المستخدم.
- قياس معالجات محددة: استخدم واجهة برمجة تطبيقات توقيت المستخدم للحصول على مزيد من التفاصيل. قم بلف معالجات الأحداث الهامة (مثل معالج 'click' لـ "إضافة إلى السلة") بـ `performance.mark()` و `performance.measure()`. سيخبرك هذا بالضبط بالمدة التي يستغرقها الكود الخاص بك للتنفيذ وما إذا كان هو مصدر المهمة الطويلة.
معالجة CLS المرتفع
يبلغ المستخدمون أن النص يقفز أثناء قراءة مقال على أجهزتهم المحمولة. درجة CLS لديك هي 0.3.
- مراقبة تحولات التخطيط: استخدم `PerformanceObserver` للاستماع إلى إدخالات `'layout-shift'`. سيكون لكل إدخال `value` (مساهمته في درجة CLS) وقائمة من `sources`، وهي عناصر DOM التي تحركت. هذا يخبرك *ماذا* تحرك.
- العثور على المورد المذنب: السؤال التالي هو *لماذا* تحرك. أحد الأسباب الشائعة هو تحميل مورد في وقت متأخر ودفع محتوى آخر لأسفل. يمكنك ربط `startTime` لإدخال `layout-shift` بوقت `responseEnd` للإدخالات من واجهة برمجة تطبيقات توقيت الموارد. إذا حدث تحول في التخطيط مباشرة بعد انتهاء تحميل سكربت إعلان أو صورة كبيرة، فمن المحتمل أنك وجدت الجاني.
- الحلول الاستباقية: غالبًا ما يتضمن الإصلاح توفير أبعاد للصور والإعلانات (`
`) أو حجز مساحة على الصفحة للمحتوى الديناميكي قبل تحميله. يساعدك توقيت الموارد في تحديد الموارد التي تحتاج إلى أن تكون استباقيًا بشأنها.
التنفيذ العملي: بناء نظام مراقبة عالمي
فهم هذه الواجهات شيء، ونشرها لمراقبة تجربة قاعدة المستخدمين العالمية الخاصة بك هو الخطوة التالية. هذا هو مجال مراقبة المستخدم الحقيقي (RUM).
تجميع كل شيء مع `PerformanceObserver`
يمكنك إنشاء سكربت واحد قوي لجمع كل هذه البيانات الهامة. الهدف هو جمع المقاييس وسياقها دون التأثير على الأداء الذي تحاول قياسه.
إليك مقتطف مفاهيمي لإعداد مراقب قوي:
const collectedMetrics = {};
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.entryType === 'largest-contentful-paint') {
collectedMetrics.lcp = entry.startTime;
} else if (entry.entryType === 'layout-shift') {
collectedMetrics.cls = (collectedMetrics.cls || 0) + entry.value;
} else if (entry.entryType === 'event') {
// This is a simplified view of INP calculation
const duration = entry.duration;
if (duration > (collectedMetrics.inp || 0)) {
collectedMetrics.inp = duration;
}
}
// ... and so on for other entry types like 'longtask'
}
});
observer.observe({ entryTypes: ['largest-contentful-paint', 'layout-shift', 'event', 'longtask'] });
إرسال البيانات بشكل موثوق
بمجرد جمع بياناتك، تحتاج إلى إرسالها إلى واجهة خلفية للتحليلات للتخزين والتحليل. من الأهمية بمكان القيام بذلك دون تأخير إلغاء تحميل الصفحة أو فقدان البيانات من المستخدمين الذين يغلقون علامات التبويب الخاصة بهم بسرعة.
تعد واجهة برمجة التطبيقات `navigator.sendBeacon()` مثالية لهذا الغرض. إنها توفر طريقة موثوقة وغير متزامنة لإرسال كمية صغيرة من البيانات إلى الخادم، حتى لو كانت الصفحة قيد إلغاء التحميل. لا تتوقع استجابة، مما يجعلها خفيفة الوزن وغير مانعة.
window.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
const payload = JSON.stringify(collectedMetrics);
navigator.sendBeacon('/api/performance-analytics', payload);
}
});
أهمية الرؤية العالمية
أدوات الاختبار المعملية مثل Lighthouse لا تقدر بثمن، لكنها تعمل في بيئة خاضعة للرقابة. تخبرك بيانات RUM التي تم جمعها من هذه الواجهات بالحقيقة الميدانية لما يختبره المستخدمون عبر مختلف البلدان وظروف الشبكة والأجهزة.
عند تحليل بياناتك، قم دائمًا بتقسيمها. قد تكتشف أن:
- مقياس LCP الخاص بك ممتاز للمستخدمين في أمريكا الشمالية ولكنه ضعيف للمستخدمين في أستراليا لأن خادم الصور الرئيسي الخاص بك موجود في الولايات المتحدة.
- مقياس INP الخاص بك مرتفع على أجهزة Android متوسطة المدى، والتي تحظى بشعبية في الأسواق الناشئة، لأن JavaScript الخاص بك يستهلك الكثير من طاقة وحدة المعالجة المركزية بالنسبة لها.
- مقياس CLS الخاص بك يمثل مشكلة فقط على أحجام شاشة معينة حيث يتسبب استعلام وسائط CSS في تغيير حجم إعلان بشكل غير صحيح.
يسمح لك هذا المستوى من الرؤية المجزأة بتحديد أولويات التحسينات التي سيكون لها التأثير الأكبر على قاعدة المستخدمين الفعلية، أينما كانوا.
الخاتمة: من القياس إلى الإتقان
لقد نضج عالم أداء الويب. لقد انتقلنا من التوقيتات التقنية البسيطة إلى فهم متطور لتجربة المستخدم المدركة. تتضمن الرحلة ثلاث خطوات رئيسية:
- قياس التجربة: استخدم `PerformanceObserver` لجمع مؤشرات أداء الويب الأساسية (LCP، INP، CLS). هذا يخبرك *بما* يحدث و*كيف يشعر به* المستخدم.
- تشخيص السبب: استخدم واجهات برمجة تطبيقات التوقيت الأساسية (التنقل، الموارد، المستخدم، المهام الطويلة) للتعمق أكثر. هذا يخبرك *لماذا* التجربة سيئة.
- التصرف بدقة: استخدم البيانات المجمعة لإجراء تحسينات مستنيرة ومستهدفة تعالج السبب الجذري للمشكلة لشرائح مستخدمين محددة.
من خلال إتقان كل من مقاييس المستخدم عالية المستوى وواجهات برمجة التطبيقات التشخيصية منخفضة المستوى، يمكنك بناء استراتيجية أداء شاملة. تتوقف عن التخمين وتبدأ في هندسة تجربة ويب ليست سريعة تقنيًا فحسب، بل تجربة تبدو سريعة وسريعة الاستجابة وممتعة لكل مستخدم، على كل جهاز، في كل مكان في العالم.