بررسی عمیق APIهای عملکرد وب، از اندازهگیریهای زمانبندی سنتی تا معیارهای مدرن کاربر محور مانند Core Web Vitals، و نحوهی اتصال آنها برای دیدگاهی جامع از عملکرد.
فراتر از زمانسنجی: اتصال APIهای عملکرد وب به تجربهی کاربری واقعی
در اقتصاد دیجیتال، سرعت فقط یک ویژگی نیست؛ بلکه پایهی تجربهی کاربری است. یک وبسایت کُند میتواند منجر به ناامیدی کاربران، نرخ پرش بالاتر و تأثیر مستقیم بر درآمد شود. سالهاست که توسعهدهندگان برای سنجش عملکرد، به معیارهای زمانبندی مانند window.onload
متکی بودهاند. اما آیا یک زمان بارگذاری سریع واقعاً برابر با یک کاربر خوشحال است؟ پاسخ اغلب منفی است.
یک صفحه میتواند تمام منابع فنی خود را در کمتر از یک ثانیه بارگیری کند، اما برای یک فرد واقعی که سعی در تعامل با آن دارد، کُند و غیرقابلاستفاده به نظر برسد. این گسست، یک تحول حیاتی در توسعهی وب را برجسته میکند: تغییر از اندازهگیری زمانبندیهای فنی به کمّیسازی تجربهی انسانی. عملکرد مدرن وب، حکایت دو دیدگاه است: دادههای دقیق و سطح پایین ارائهشده توسط APIهای عملکرد وب و معیارهای سطح بالا و کاربر محور مانند Core Web Vitals گوگل.
این راهنمای جامع این شکاف را پُر میکند. ما مجموعهی قدرتمند APIهای عملکرد وب را که به عنوان ابزارهای تشخیصی ما عمل میکنند، بررسی خواهیم کرد. سپس، به معیارهای مدرن تجربهی کاربری میپردازیم که به ما میگویند عملکرد *چگونه احساس میشود*. مهمتر از همه، ما نقاط را به هم متصل میکنیم و به شما نشان میدهیم که چگونه از دادههای زمانبندی سطح پایین برای تشخیص و رفع علل اصلی تجربهی کاربری ضعیف برای مخاطبان جهانی خود استفاده کنید.
مبانی: درک APIهای عملکرد وب
APIهای عملکرد وب مجموعهای از رابطهای مرورگر استانداردشده هستند که به توسعهدهندگان امکان دسترسی به دادههای زمانبندی بسیار دقیق و مرتبط با ناوبری و رندر یک صفحهی وب را میدهند. آنها سنگ بنای اندازهگیری عملکرد هستند و به ما این امکان را میدهند که فراتر از کرنومترهای ساده حرکت کنیم و رقص پیچیدهی درخواستهای شبکه، تجزیه و رندر را درک کنیم.
Navigation Timing API: سفر صفحه
Navigation Timing API یک تفکیک دقیق از زمانی که برای بارگیری سند اصلی صرف میشود، ارائه میدهد. این API نقاط عطفی را از لحظهای که یک کاربر ناوبری را آغاز میکند (مانند کلیک کردن روی یک پیوند) تا لحظهای که صفحه به طور کامل بارگیری میشود، ثبت میکند. این اولین و اساسیترین دیدگاه ما نسبت به فرآیند بارگیری صفحه است.
شما میتوانید با یک فراخوانی سادهی جاوااسکریپت به این دادهها دسترسی پیدا کنید:
const navigationEntry = performance.getEntriesByType('navigation')[0];
console.log(navigationEntry.toJSON());
این یک شیء پُر از مُهرهای زمانی را برمیگرداند. برخی از ویژگیهای کلیدی عبارتند از:
- fetchStart: زمانی که مرورگر شروع به واکشی سند میکند.
- responseStart: زمانی که مرورگر اولین بایت پاسخ را از سرور دریافت میکند. زمان بین
fetchStart
وresponseStart
اغلب به عنوان Time to First Byte (TTFB) نامیده میشود. - domContentLoadedEventEnd: زمانی که سند HTML اولیه به طور کامل بارگیری و تجزیه شده است، بدون انتظار برای اتمام بارگیری برگههای سبک، تصاویر و زیرفریمها.
- loadEventEnd: زمانی که تمام منابع برای صفحه (شامل تصاویر، CSS و غیره) به طور کامل بارگیری شدهاند.
برای مدت طولانی، loadEventEnd
استاندارد طلایی بود. با این حال، محدودیت آن شدید است: چیزی در مورد زمانی که کاربر محتوای معنادار را *میبیند* یا زمانی که میتواند با صفحه *تعامل* داشته باشد، نمیگوید. این یک نقطهی عطف فنی است، نه یک نقطهی عطف انسانی.
Resource Timing API: تجزیهی اجزا
یک صفحهی وب به ندرت یک فایل تکی است. این مجموعهای از HTML، CSS، جاوااسکریپت، تصاویر، فونتها و فراخوانیهای API است. Resource Timing API به شما امکان میدهد زمانبندی شبکه را برای هر یک از این منابع جداگانه بررسی کنید.
این برای شناسایی گلوگاهها فوقالعاده قدرتمند است. آیا یک تصویر بزرگ و بهینهنشدهی hero از یک شبکهی تحویل محتوا (CDN) در قارهای دیگر، رندر اولیهی صفحه را کُند میکند؟ آیا یک اسکریپت تجزیهوتحلیل شخص ثالث، رشتهی اصلی را مسدود میکند؟ Resource Timing به شما کمک میکند به این سؤالات پاسخ دهید.
شما میتوانید لیستی از تمام منابع را به این صورت دریافت کنید:
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) شما پس از دریافت داده از یک API، یک مؤلفهی پیچیده را رندر کند؟ User Timing API به شما امکان میدهد اندازهگیریهای سفارشی و مختص برنامه ایجاد کنید.
این API با دو روش اصلی کار میکند:
- performance.mark(name): یک مُهر زمانی نامگذاریشده در بافر عملکرد ایجاد میکند.
- performance.measure(name, startMark, endMark): مدت زمان بین دو مُهر را محاسبه میکند و یک اندازهگیری نامگذاریشده ایجاد میکند.
مثال: اندازهگیری زمان رندر یک مؤلفهی لیست محصولات.
// When you start fetching data
performance.mark('product-list-fetch-start');
fetch('/api/products')
.then(response => response.json())
.then(data => {
// After fetching, before rendering
performance.mark('product-list-render-start');
renderProductList(data);
// Immediately after rendering is complete
performance.mark('product-list-render-end');
// Create a measure
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'] });
این observer کلید جمعآوری نه تنها معیارهای سنتی فوق، بلکه معیارهای مدرن و کاربر محور است که در ادامه به آنها خواهیم پرداخت.
تغییر به سمت کاربرمحوری: Core Web Vitals
دانستن اینکه یک صفحه در 2 ثانیه بارگیری شده است مفید است، اما به سؤالات حیاتی پاسخ نمیدهد: آیا کاربر در این 2 ثانیه به یک صفحهی خالی خیره شده است؟ آیا میتوانست با صفحه تعامل داشته باشد یا مسدود شده بود؟ آیا محتوا به طور غیرمنتظرهای در حین تلاش برای خواندن، به اطراف میپرید؟
برای پرداختن به این موضوع، گوگل Core Web Vitals (CWV) را معرفی کرد، مجموعهای از معیارها که برای اندازهگیری تجربهی کاربر واقعی یک صفحه در سه بعد کلیدی طراحی شدهاند: بارگیری، تعامل و ثبات بصری.
Largest Contentful Paint (LCP): اندازهگیری بارگیری ادراکشده
LCP زمان رندر بزرگترین تصویر یا بلوک متنی قابل مشاهده در درگاه دید را اندازهگیری میکند. این یک پروکسی عالی برای زمانی است که کاربر احساس میکند محتوای اصلی صفحه بارگیری شده است. این مستقیماً به سؤال کاربر پاسخ میدهد: "آیا این صفحه هنوز مفید است؟"
- خوب: زیر 2.5 ثانیه
- نیاز به بهبود: بین 2.5 ثانیه و 4.0 ثانیه
- ضعیف: بالای 4.0 ثانیه
برخلاف loadEventEnd
، LCP بر آنچه کاربر ابتدا میبیند تمرکز میکند و آن را بازتاب بسیار دقیقتری از سرعت بارگذاری ادراکشده میکند.
Interaction to Next Paint (INP): اندازهگیری پاسخگویی
INP جانشین First Input Delay (FID) است و در مارس 2024 به یک Core Web Vital رسمی تبدیل شد. در حالی که FID فقط تأخیر *اولین* تعامل را اندازهگیری میکرد، INP تأخیر *تمام* تعاملات کاربر (کلیکها، ضربهها، فشار دادن کلیدها) را در طول چرخهی حیات صفحه اندازهگیری میکند. این معیار طولانیترین تعامل را گزارش میکند و به طور مؤثر بدترین حالت پاسخگویی را که یک کاربر تجربه میکند، شناسایی میکند.
INP کل زمان از ورودی کاربر تا زمانی که فریم بعدی ترسیم شود را اندازهگیری میکند و بازخورد بصری را منعکس میکند. این به سؤال کاربر پاسخ میدهد: "وقتی روی این دکمه کلیک میکنم، آیا صفحه به سرعت پاسخ میدهد؟"
- خوب: زیر 200 میلیثانیه
- نیاز به بهبود: بین 200 میلیثانیه و 500 میلیثانیه
- ضعیف: بالای 500 میلیثانیه
INP بالا معمولاً ناشی از یک رشتهی اصلی شلوغ است، جایی که وظایف جاوااسکریپت طولانیمدت از پاسخگویی مرورگر به ورودی کاربر جلوگیری میکنند.
Cumulative Layout Shift (CLS): اندازهگیری ثبات بصری
CLS ثبات بصری یک صفحه را اندازهگیری میکند. این معیار کمیت میدهد که چقدر محتوا به طور غیرمنتظرهای در طول فرآیند بارگیری روی صفحه حرکت میکند. امتیاز CLS بالا یک منبع رایج ناامیدی کاربر است، مانند زمانی که سعی میکنید روی یک دکمه کلیک کنید، اما یک تبلیغ در بالای آن بارگیری میشود و دکمه را به پایین میبرد و باعث میشود به جای آن روی تبلیغ کلیک کنید.
CLS به سؤال کاربر پاسخ میدهد: "آیا میتوانم از این صفحه استفاده کنم بدون اینکه عناصر در همه جا بپرند؟"
- خوب: زیر 0.1
- نیاز به بهبود: بین 0.1 و 0.25
- ضعیف: بالای 0.25
علل شایع CLS بالا شامل تصاویر یا iframes بدون ابعاد، بارگیری دیرهنگام فونتهای وب یا تزریق پویای محتوا به صفحه بدون رزرو فضا برای آن است.
پُر کردن شکاف: استفاده از APIها برای تشخیص تجربهی کاربری ضعیف
اینجاست که همه چیز به هم میرسد. Core Web Vitals به ما میگوید *چه* چیزی را کاربر تجربه کرده است (به عنوان مثال، یک LCP کُند). APIهای عملکرد وب به ما میگوید *چرا* این اتفاق افتاده است. با ترکیب آنها، ما از صرفاً مشاهدهی عملکرد به تشخیص فعالانه و رفع آن تبدیل میشویم.
تشخیص یک LCP کُند
تصور کنید ابزار Real User Monitoring (RUM) شما یک LCP ضعیف 4.5 ثانیهای را برای کاربران در یک منطقهی خاص گزارش میدهد. چگونه آن را رفع میکنید؟ شما باید زمان LCP را به اجزای تشکیلدهندهی آن تقسیم کنید.
- Time to First Byte (TTFB): آیا پاسخگویی سرور کُند است؟ از Navigation Timing API استفاده کنید. مدت زمان
responseStart - requestStart
یک TTFB دقیق به شما میدهد. اگر این مقدار زیاد باشد، مشکل در باطن، پیکربندی سرور یا پایگاه دادهی شماست، نه فرانتاند. - Resource Load Delay & Time: آیا خود عنصر LCP به کندی بارگیری میشود؟ ابتدا عنصر LCP را شناسایی کنید (به عنوان مثال، یک تصویر hero). میتوانید از یک
PerformanceObserver
برای'largest-contentful-paint'
برای دریافت خود عنصر استفاده کنید. سپس، از Resource Timing API برای یافتن ورودی URL آن عنصر استفاده کنید. جدول زمانی آن را تجزیهوتحلیل کنید: آیا یکconnectStart
طولانی بهconnectEnd
وجود داشت (شبکهی کُند)؟ آیاresponseStart
بهresponseEnd
طولانی بود (یک اندازهی فایل بسیار بزرگ)؟ آیاfetchStart
آن به این دلیل به تأخیر افتاد که توسط سایر منابع مسدودکنندهی رندر مانند CSS یا جاوااسکریپت مسدود شده بود؟ - Element Render Delay: این زمان پس از اتمام بارگیری منبع تا زمانی است که در واقع روی صفحه ترسیم شود. این میتواند ناشی از مشغول بودن رشتهی اصلی با سایر وظایف، مانند اجرای یک بستهی جاوااسکریپت بزرگ باشد.
با استفاده از Navigation و Resource Timing، میتوانید مشخص کنید که آیا یک LCP کُند به دلیل یک سرور کُند، یک اسکریپت مسدودکنندهی رندر یا یک تصویر بزرگ و بهینهنشده است.
بررسی INP ضعیف
کاربران شما شکایت دارند که کلیک کردن روی دکمهی "افزودن به سبد خرید" احساس تاخیری دارد. معیار INP شما در محدودهی "ضعیف" است. این تقریباً همیشه یک مشکل رشتهی اصلی است.
- شناسایی وظایف طولانی: Long Tasks API ابزار اصلی شما در اینجا است. این API هر وظیفهای را در رشتهی اصلی که بیش از 50 میلیثانیه طول میکشد گزارش میکند، زیرا هر چیزی طولانیتر از آن خطر ایجاد تاخیر قابل توجهی برای کاربر را دارد. یک
PerformanceObserver
را برای گوش دادن به ورودیهای'longtask'
تنظیم کنید. - همبستگی با اقدامات کاربر: یک وظیفهی طولانی فقط در صورتی مشکلساز است که هنگام تلاش کاربر برای تعامل رخ دهد. میتوانید
startTime
یک رویداد INP (مشاهدهشده از طریقPerformanceObserver
در نوع'event'
) را با زمانبندی هر وظیفهی طولانی که در همان زمان رخ داده است، مرتبط کنید. این به شما دقیقاً میگوید که کدام تابع جاوااسکریپت تعامل کاربر را مسدود کرده است. - اندازهگیری کنترلکنندههای خاص: از User Timing API برای دستیابی به جزئیات بیشتر استفاده کنید. کنترلکنندههای رویداد حیاتی خود (مانند کنترلکنندهی 'click' برای "افزودن به سبد خرید") را با
performance.mark()
وperformance.measure()
بپیچید. این به شما دقیقاً میگوید که کد خودتان چقدر طول میکشد تا اجرا شود و آیا این منبع وظیفهی طولانی است یا خیر.
مقابله با CLS بالا
کاربران گزارش میدهند که متن هنگام خواندن یک مقاله در دستگاههای تلفن همراه خود به اطراف میپرد. امتیاز CLS شما 0.3 است.
- مشاهدهی جابهجاییهای طرحبندی: از یک
PerformanceObserver
برای گوش دادن به ورودیهای'layout-shift'
استفاده کنید. هر ورودی یکvalue
(سهم آن در امتیاز CLS) و یک لیست ازsources
خواهد داشت که عناصر DOM هستند که جابهجا شدهاند. این به شما میگوید *چه چیزی* جابهجا شده است. - یافتن منبع مشکل: سؤال بعدی این است که *چرا* جابهجا شده است. یک دلیل رایج بارگیری دیرهنگام یک منبع و پایین بردن سایر محتوا است. میتوانید
startTime
یک ورودیlayout-shift
را با زمانresponseEnd
ورودیها از Resource Timing API مرتبط کنید. اگر یک جابهجایی طرحبندی بلافاصله پس از اتمام بارگیری یک اسکریپت تبلیغاتی یا یک تصویر بزرگ رخ دهد، احتمالاً منبع مشکل خود را پیدا کردهاید. - راهحلهای پیشگیرانه: رفع این مشکل اغلب شامل ارائهی ابعاد برای تصاویر و تبلیغات (
) یا رزرو فضا در صفحه برای محتوای پویا قبل از بارگیری آن است. Resource Timing به شما کمک میکند تا مشخص کنید کدام منابع را باید در مورد آنها پیشگیرانه باشید.
پیادهسازی عملی: ساخت یک سیستم نظارت جهانی
درک این APIها یک چیز است. استقرار آنها برای نظارت بر تجربهی پایگاه کاربران جهانی شما، گام بعدی است. این حوزهی Real User Monitoring (RUM) است.
جمعآوری همه چیز با PerformanceObserver
میتوانید یک اسکریپت قدرتمند واحد برای جمعآوری تمام این دادههای حیاتی ایجاد کنید. هدف جمعآوری معیارها و زمینهی آنها بدون تأثیر بر عملکردی است که سعی در اندازهگیری آن دارید.
در اینجا یک قطعهی مفهومی از یک تنظیمات observer قوی وجود دارد:
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'] });
ارسال داده به طور قابل اعتماد
پس از جمعآوری دادههای خود، باید آن را به یک باطن تجزیهوتحلیل برای ذخیرهسازی و تجزیهوتحلیل ارسال کنید. بسیار مهم است که این کار را بدون به تاخیر انداختن تخلیهی صفحه یا از دست دادن داده از کاربرانی که به سرعت تبهای خود را میبندند، انجام دهید.
API navigator.sendBeacon()
برای این کار عالی است. این یک روش ناهمزمان و قابل اعتماد برای ارسال مقدار کمی داده به یک سرور، حتی اگر صفحه در حال تخلیه باشد، ارائه میدهد. این API انتظار پاسخ ندارد و آن را سبک وزن و غیر مسدودکننده میکند.
window.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
const payload = JSON.stringify(collectedMetrics);
navigator.sendBeacon('/api/performance-analytics', payload);
}
});
اهمیت یک دیدگاه جهانی
ابزارهای آزمایشگاهی مانند Lighthouse ارزشمند هستند، اما در یک محیط کنترلشده اجرا میشوند. دادههای RUM جمعآوریشده از این APIها به شما حقیقت اساسی آنچه را که کاربران شما در سراسر کشورهای مختلف، شرایط شبکه و دستگاهها تجربه میکنند، میگوید.
هنگام تجزیهوتحلیل دادههای خود، همیشه آن را بخشبندی کنید. ممکن است کشف کنید که:
- LCP شما برای کاربران در آمریکای شمالی عالی است، اما برای کاربران در استرالیا ضعیف است، زیرا سرور تصویر اصلی شما در ایالات متحده مستقر است.
- INP شما در دستگاههای Android میانرده، که در بازارهای نوظهور محبوب هستند، زیاد است، زیرا جاوااسکریپت شما برای آنها بیش از حد CPU-محور است.
- CLS شما فقط در اندازههای صفحهی خاصی مشکلساز است که در آن یک پرسوجوی رسانهای CSS باعث تغییر اندازهی نامناسب یک تبلیغ میشود.
این سطح از بینش بخشبندیشده به شما امکان میدهد بهینهسازیهایی را اولویتبندی کنید که بیشترین تأثیر را بر پایگاه کاربران واقعی شما، در هر کجا که هستند، خواهند داشت.
نتیجهگیری: از اندازهگیری تا تسلط
دنیای عملکرد وب بالغ شده است. ما از زمانبندیهای فنی ساده به درک پیچیدهای از تجربهی ادراکشدهی کاربر رسیدهایم. این سفر شامل سه مرحلهی کلیدی است:
- اندازهگیری تجربه: از
PerformanceObserver
برای جمعآوری Core Web Vitals (LCP, INP, CLS) استفاده کنید. این به شما میگوید *چه* اتفاقی میافتد و *چه حسی* به کاربر میدهد. - تشخیص علت: از APIهای زمانبندی اساسی (Navigation, Resource, User, Long Tasks) برای بررسی عمیقتر استفاده کنید. این به شما میگوید *چرا* تجربه ضعیف است.
- اقدام با دقت: از دادههای ترکیبی برای انجام بهینهسازیهای آگاهانه و هدفمند استفاده کنید که علت اصلی مشکل را برای بخشهای کاربری خاص برطرف میکند.
با تسلط بر معیارهای کاربر سطح بالا و APIهای تشخیصی سطح پایین، میتوانید یک استراتژی عملکرد جامع بسازید. شما از حدس زدن دست برمیدارید و شروع به مهندسی یک تجربهی وب میکنید که نه تنها از نظر فنی سریع است، بلکه احساس سرعت، پاسخگویی و لذتبخش بودن را برای هر کاربر، در هر دستگاه، در هر کجای دنیا میدهد.