داشتن معیارهای کاربرمحور که بتوانید به صورت جهانی و در هر وبسایتی اندازهگیری کنید، ارزش زیادی دارد. این معیارها به شما امکان میدهند:
- درک کنید که کاربران واقعی چگونه وب را به طور کلی تجربه میکنند.
- سایت خود را با سایت رقبا مقایسه کنید.
- بدون نیاز به نوشتن کد سفارشی، دادههای مفید و کاربردی را در ابزارهای تحلیلی خود پیگیری کنید.
معیارهای جهانی، مبنای خوبی ارائه میدهند، اما در بسیاری از موارد، برای درک کامل تجربه کاربری سایت خاص خود، باید بیش از این معیارها را اندازهگیری کنید.
معیارهای سفارشی به شما امکان میدهند جنبههایی از تجربه سایت خود را که ممکن است فقط در مورد سایت شما صدق کند، اندازهگیری کنید، مانند:
- مدت زمانی که طول میکشد تا یک برنامه تک صفحهای (SPA) از یک "صفحه" به صفحه دیگر منتقل شود.
- مدت زمانی که طول میکشد تا یک صفحه، دادههای واکشی شده از پایگاه داده را برای کاربران وارد شده نمایش دهد.
- چقدر طول میکشد تا یک برنامه رندر شده سمت سرور (SSR) هیدراته شود؟
- نرخ بازدید از حافظه پنهان برای منابع بارگذاری شده توسط بازدیدکنندگان برگشتی.
- تأخیر رویداد کلیک یا رویدادهای صفحه کلید در یک بازی.
APIها برای اندازهگیری معیارهای سفارشی
از نظر تاریخی، توسعهدهندگان وب APIهای سطح پایین زیادی برای سنجش عملکرد نداشتهاند و در نتیجه، برای سنجش عملکرد خوب یک سایت، مجبور بودهاند به هکها متوسل شوند.
برای مثال، میتوان با اجرای یک حلقه requestAnimationFrame و محاسبه دلتا بین هر فریم، مشخص کرد که آیا رشته اصلی به دلیل وظایف طولانی مدت جاوا اسکریپت مسدود شده است یا خیر. اگر دلتا به طور قابل توجهی طولانیتر از نرخ فریم صفحه نمایش باشد، میتوانید آن را به عنوان یک وظیفه طولانی گزارش دهید. با این حال، چنین هکهایی توصیه نمیشوند، زیرا در واقع خودشان بر عملکرد تأثیر میگذارند (مثلاً با تخلیه باتری).
اولین قانون اندازهگیری عملکرد مؤثر این است که مطمئن شوید تکنیکهای اندازهگیری عملکرد شما خودشان باعث مشکلات عملکردی نمیشوند. بنابراین برای هر معیار سفارشی که در سایت خود اندازهگیری میکنید، بهتر است در صورت امکان از یکی از API های زیر استفاده کنید.
API ناظر عملکرد
رابط برنامهنویسی کاربردی (API) ناظر عملکرد، مکانیزمی است که دادهها را از سایر رابطهای برنامهنویسی کاربردی عملکرد که در این صفحه مورد بحث قرار گرفتهاند، جمعآوری و نمایش میدهد. درک آن برای دستیابی به دادههای خوب بسیار مهم است.
شما میتوانید PerformanceObserver برای اشتراک غیرفعال در رویدادهای مرتبط با عملکرد استفاده کنید. این کار به API Callbackها اجازه میدهد در دورههای بیکاری اجرا شوند، به این معنی که معمولاً در عملکرد صفحه اختلالی ایجاد نمیکنند.
برای ایجاد یک PerformanceObserver ، یک تابع فراخوانی (callback) به آن ارسال کنید تا هر زمان که ورودیهای عملکردی جدید ارسال شدند، اجرا شود. سپس با استفاده از متد observe() به observer میگویید که به چه نوع ورودیهایی گوش دهد:
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
po.observe({type: 'some-entry-type'});
بخشهای زیر انواع مختلف ورودیهای موجود برای مشاهده را فهرست میکنند، اما در مرورگرهای جدیدتر، میتوانید از طریق ویژگی استاتیک PerformanceObserver.supportedEntryTypes بررسی کنید که چه نوع ورودیهایی در دسترس هستند.
مشاهده ورودیهایی که قبلاً اتفاق افتادهاند
به طور پیشفرض، اشیاء PerformanceObserver فقط میتوانند ورودیها را در زمان وقوع مشاهده کنند. این میتواند در صورتی که بخواهید کد تجزیه و تحلیل عملکرد خود را به صورت lazy-load بارگذاری کنید تا منابع با اولویت بالاتر مسدود نشوند، مشکلاتی ایجاد کند.
برای دریافت ورودیهای تاریخی (پس از وقوع)، هنگام فراخوانی observe() ، پرچم buffered را روی true تنظیم کنید. مرورگر ورودیهای تاریخی را از بافر ورودی عملکرد خود، اولین باری که فراخوانی PerformanceObserver شما انجام میشود، تا حداکثر اندازه بافر برای آن نوع، لحاظ خواهد کرد.
po.observe({
type: 'some-entry-type',
buffered: true,
});
APIهای عملکردی قدیمی که باید از آنها اجتناب کنید
قبل از رابط برنامهنویسی کاربردی Performance Observer، توسعهدهندگان میتوانستند با استفاده از سه روش زیر که در شیء performance تعریف شده بودند، به ورودیهای performance دسترسی پیدا کنند:
اگرچه این APIها هنوز پشتیبانی میشوند، استفاده از آنها توصیه نمیشود زیرا به شما اجازه نمیدهند زمان انتشار ورودیهای جدید را پیگیری کنید. علاوه بر این، بسیاری از APIهای جدید (مانند largest-contentful-paint ) از طریق شیء performance نمایش داده نمیشوند، بلکه فقط از طریق PerformanceObserver نمایش داده میشوند.
مگر اینکه به طور خاص به سازگاری با اینترنت اکسپلورر نیاز داشته باشید، بهتر است از این متدها در کد خود اجتناب کنید و از این به بعد PerformanceObserver استفاده کنید.
API زمانبندی کاربر
رابط برنامهنویسی کاربردی زمانبندی کاربر (User Timing API) یک رابط برنامهنویسی کاربردی اندازهگیری عمومی برای معیارهای مبتنی بر زمان است. این رابط به شما امکان میدهد نقاط دلخواه را در زمان علامتگذاری کنید و سپس بعداً مدت زمان بین آن علامتها را اندازهگیری کنید.
// Record the time immediately before running a task.
performance.mark('myTask:start');
await doMyTask();
// Record the time immediately after running a task.
performance.mark('myTask:end');
// Measure the delta between the start and end of the task
performance.measure('myTask', 'myTask:start', 'myTask:end');
در حالی که APIهایی مانند Date.now() یا performance.now() قابلیتهای مشابهی را در اختیار شما قرار میدهند، مزیت استفاده از API زمانبندی کاربر این است که به خوبی با ابزارهای عملکرد ادغام میشود. به عنوان مثال، Chrome DevTools اندازهگیریهای زمانبندی کاربر را در پنل Performance به تصویر میکشد و بسیاری از ارائهدهندگان تجزیه و تحلیل نیز به طور خودکار هر اندازهگیری که انجام میدهید را ردیابی کرده و دادههای مدت زمان را به backend تجزیه و تحلیل خود ارسال میکنند.
برای گزارش اندازهگیریهای زمانبندی کاربر، میتوانید از PerformanceObserver استفاده کنید و ورودیهایی از نوع measure را برای مشاهده ثبت کنید:
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `measure` entries to be dispatched.
po.observe({type: 'measure', buffered: true});
API وظایف طولانی
API مربوط به وظایف طولانی (Long Tasks API) برای دانستن اینکه چه زمانی رشته اصلی مرورگر برای مدت زمان کافی مسدود شده است تا بر نرخ فریم یا تأخیر ورودی تأثیر بگذارد، مفید است. این API هر وظیفهای را که بیش از ۵۰ میلیثانیه اجرا شود، گزارش میدهد.
هر زمان که نیاز به اجرای کد سنگین یا بارگذاری و اجرای اسکریپتهای بزرگ دارید، ردیابی اینکه آیا آن کد، نخ اصلی را مسدود میکند یا خیر، مفید است. در واقع، بسیاری از معیارهای سطح بالاتر بر اساس خود API وظایف طولانی ساخته شدهاند (مانند زمان تعامل (TTI) و زمان کل مسدودسازی (TBT) ).
برای تعیین زمان وقوع وظایف طولانی، میتوانید از PerformanceObserver استفاده کنید و ورودیهایی از نوع longtask را ثبت کنید تا مشاهده شوند:
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `longtask` entries to be dispatched.
po.observe({type: 'longtask', buffered: true});
API فریمهای انیمیشن بلند
API فریمهای انیمیشن بلند (Long Animation Frames API) نسخهی جدیدی از API وظایف بلند (Long Tasks API) است که به فریمهای بلند - به جای وظایف بلند - با طول بیش از ۵۰ میلیثانیه میپردازد. این API برخی از کاستیهای API وظایف بلند ، از جمله تخصیص بهتر و دامنهی وسیعتر تأخیرهای بالقوه مشکلساز را برطرف میکند.
برای تعیین زمان وقوع فریمهای طولانی، میتوانید از PerformanceObserver استفاده کنید و ورودیهایی از نوع long-animation-frame را ثبت کنید تا مشاهده شوند:
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `long-animation-frame` entries to be dispatched.
po.observe({type: 'long-animation-frame', buffered: true});
API زمانبندی عناصر
معیار بزرگترین رنگ محتوا (LCP) برای دانستن زمان رنگآمیزی بزرگترین تصویر یا بلوک متن روی صفحه مفید است، اما در برخی موارد میخواهید زمان رندر یک عنصر متفاوت را اندازهگیری کنید.
برای این موارد، از API زمانبندی عنصر استفاده کنید. API LCP در واقع بر روی API زمانبندی عنصر ساخته شده است و گزارش خودکار بزرگترین عنصر محتوایی را اضافه میکند، اما میتوانید با اضافه کردن صریح ویژگی elementtiming به عناصر دیگر و ثبت یک PerformanceObserver برای مشاهده نوع ورودی element ، در مورد آنها نیز گزارش دهید.
<img elementtiming="hero-image" />
<p elementtiming="important-paragraph">This is text I care about.</p>
<!-- ... -->
<script>
const po = new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `element` entries to be dispatched.
po.observe({type: 'element', buffered: true});
</script>
API زمانبندی رویداد
معیار تعامل تا نمایش بعدی (INP) با مشاهده تمام تعاملات کلیک، لمس و صفحهکلید در طول عمر یک صفحه، میزان پاسخگویی کلی صفحه را ارزیابی میکند. INP یک صفحه اغلب تعاملی است که بیشترین زمان را برای تکمیل شدن صرف کرده است، از زمانی که کاربر تعامل را آغاز کرده تا زمانی که مرورگر فریم بعدی را که نتیجه بصری ورودی کاربر را نشان میدهد، نمایش میدهد.
معیار INP توسط API زمانبندی رویداد امکانپذیر است. این API تعدادی از مهرهای زمانی را که در طول چرخه حیات رویداد رخ میدهند، از جمله موارد زیر، در معرض نمایش قرار میدهد:
-
startTime: زمانی که مرورگر رویداد را دریافت میکند. -
processingStart: زمانی که مرورگر قادر به شروع پردازش کنترلکنندههای رویداد برای رویداد است. -
processingEnd: زمانی که مرورگر اجرای تمام کدهای همزمان آغاز شده از event handlerها برای این رویداد را به پایان میرساند. -
durationزمان (به دلایل امنیتی به ۸ میلیثانیه گرد شده است) بین زمانی که مرورگر رویداد را دریافت میکند تا زمانی که بتواند فریم بعدی را پس از اتمام اجرای تمام کدهای همزمان آغاز شده از کنترلکنندههای رویداد، ترسیم کند.
مثال زیر نحوه استفاده از این مقادیر برای ایجاد اندازهگیریهای سفارشی را نشان میدهد:
const po = new PerformanceObserver((entryList) => {
// Get the last interaction observed:
const entries = Array.from(entryList.getEntries()).forEach((entry) => {
// Get various bits of interaction data:
const inputDelay = entry.processingStart - entry.startTime;
const processingTime = entry.processingEnd - entry.processingStart;
const presentationDelay = entry.startTime + entry.duration - entry.processingEnd;
const duration = entry.duration;
const eventType = entry.name;
const target = entry.target || "(not set)"
console.log("----- INTERACTION -----");
console.log(`Input delay (ms): ${inputDelay}`);
console.log(`Event handler processing time (ms): ${processingTime}`);
console.log(`Presentation delay (ms): ${presentationDelay}`);
console.log(`Total event duration (ms): ${duration}`);
console.log(`Event type: ${eventType}`);
console.log(target);
});
});
// A durationThreshold of 16ms is necessary to include more
// interactions, since the default is 104ms. The minimum
// durationThreshold is 16ms.
po.observe({type: 'event', buffered: true, durationThreshold: 16});
API زمانبندی منابع
API زمانبندی منابع (Resource Timing API) به توسعهدهندگان بینش دقیقی در مورد نحوه بارگذاری منابع برای یک صفحه خاص ارائه میدهد. علیرغم نام API، اطلاعاتی که ارائه میدهد فقط به دادههای زمانبندی محدود نمیشود (هرچند که مقدار زیادی از آن وجود دارد). سایر دادههایی که میتوانید به آنها دسترسی داشته باشید عبارتند از:
-
initiatorType: نحوهی دریافت منبع: مثلاً از یک تگ<script>یا<link>یا از یک فراخوانیfetch(). -
nextHopProtocol: پروتکلی که برای دریافت منبع استفاده میشود، مانندh2یاquic. -
encodedBodySize/ decodedBodySize ]: اندازه منبع در شکل رمزگذاری شده یا رمزگشایی شده آن (به ترتیب) -
transferSize: اندازه منبعی که در واقع از طریق شبکه منتقل شده است. هنگامی که منابع توسط حافظه پنهان (cache) پر میشوند، این مقدار میتواند بسیار کوچکتر ازencodedBodySizeباشد و در برخی موارد میتواند صفر باشد (اگر نیازی به اعتبارسنجی مجدد حافظه پنهان نباشد).
شما میتوانید از ویژگی transferSize در ورودیهای زمانبندی منابع برای اندازهگیری معیار نرخ موفقیت در حافظه پنهان یا معیار اندازه کل منابع ذخیرهشده در حافظه پنهان استفاده کنید، که میتواند در درک چگونگی تأثیر استراتژی ذخیرهسازی منابع شما بر عملکرد بازدیدکنندگان تکراری مفید باشد.
مثال زیر تمام منابع درخواست شده توسط صفحه را ثبت میکند و نشان میدهد که آیا هر منبع توسط حافظه پنهان (cache) برآورده شده است یا خیر.
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// If transferSize is 0, the resource was fulfilled using the cache.
console.log(entry.name, entry.transferSize === 0);
}
});
// Start listening for `resource` entries to be dispatched.
po.observe({type: 'resource', buffered: true});
API زمانبندی ناوبری
رابط برنامهنویسی زمانبندی ناوبری (Navigation Timing API) مشابه رابط برنامهنویسی زمانبندی منابع (Resource Timing API) است، اما فقط درخواستهای ناوبری را گزارش میدهد. نوع ورودی navigation entry type) نیز مشابه نوع ورودی resource (resource entry type) است، اما شامل برخی اطلاعات اضافی است که مختص درخواستهای ناوبری است (مانند زمانی که رویدادهای DOMContentLoaded و load فعال میشوند).
یکی از معیارهایی که بسیاری از توسعهدهندگان برای درک زمان پاسخگویی سرور دنبال میکنند ( زمان اولین بایت (TTFB) ) با استفاده از API زمانبندی ناوبری در دسترس است - به طور خاص، مهر زمانی responseStart ورودی آن است.
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// If transferSize is 0, the resource was fulfilled using the cache.
console.log('Time to first byte', entry.responseStart);
}
});
// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});
یکی دیگر از معیارهایی که توسعهدهندگانی که از سرویس ورکر استفاده میکنند ممکن است به آن اهمیت دهند، زمان راهاندازی سرویس ورکر برای درخواستهای ناوبری است. این مدت زمانی است که مرورگر طول میکشد تا نخ سرویس ورکر را قبل از اینکه بتواند شروع به رهگیری رویدادهای واکشی کند، شروع کند.
زمان راهاندازی سرویس ورکر برای یک درخواست ناوبری خاص را میتوان از اختلاف بین entry.responseStart و entry.workerStart تعیین کرد.
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log('Service Worker startup time:',
entry.responseStart - entry.workerStart);
}
});
// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});
API زمانبندی سرور
API زمانبندی سرور به شما امکان میدهد دادههای زمانبندی خاص درخواست را از سرور خود از طریق هدرهای پاسخ به مرورگر منتقل کنید. به عنوان مثال، میتوانید مشخص کنید که جستجوی دادهها در یک پایگاه داده برای یک درخواست خاص چقدر طول کشیده است - که میتواند در اشکالزدایی مشکلات عملکرد ناشی از کندی در سرور مفید باشد.
برای توسعهدهندگانی که از ارائهدهندگان تجزیه و تحلیل شخص ثالث استفاده میکنند، API زمانبندی سرور تنها راه برای مرتبط کردن دادههای عملکرد سرور با سایر معیارهای تجاری است که این ابزارهای تحلیلی ممکن است اندازهگیری کنند.
برای مشخص کردن دادههای زمانبندی سرور در پاسخهایتان، میتوانید از هدر پاسخ Server-Timing استفاده کنید. در اینجا یک مثال آورده شده است.
HTTP/1.1 200 OK
Server-Timing: miss, db;dur=53, app;dur=47.2
سپس، از صفحات خود، میتوانید این دادهها را هم در ورودیهای resource و هم در ورودیهای navigation از APIهای زمانبندی منابع و زمانبندی ناوبری بخوانید.
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Logs all server timing data for this response
console.log('Server Timing', entry.serverTiming);
}
});
// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});