ارزش زیادی در داشتن معیارهای کاربر محور وجود دارد که می توانید به طور جهانی در هر وب سایتی اندازه گیری کنید. این معیارها به شما امکان می دهند:
- درک کنید که کاربران واقعی چگونه وب را به عنوان یک کل تجربه می کنند.
- سایت خود را با یک رقیب مقایسه کنید.
- داده های مفید و کاربردی را در ابزارهای تحلیلی خود بدون نیاز به نوشتن کد سفارشی ردیابی کنید.
معیارهای جهانی پایه خوبی را ارائه می دهند، اما در بسیاری از موارد شما نیاز به اندازه گیری بیش از این معیارها دارید تا تجربه کاملی را برای سایت خاص خود به دست آورید.
معیارهای سفارشی به شما امکان می دهد جنبه هایی از تجربه سایت خود را که ممکن است فقط در مورد سایت شما اعمال شود، اندازه گیری کنید، مانند:
- چه مدت طول می کشد تا یک برنامه تک صفحه ای (SPA) از یک "صفحه" به صفحه دیگر منتقل شود.
- چقدر طول می کشد تا یک صفحه داده های واکشی شده از پایگاه داده را برای کاربرانی که وارد سیستم شده اند نمایش دهد.
- چه مدت طول می کشد تا یک برنامه رندر شده از سمت سرور (SSR) هیدراته شود.
- نرخ ضربه حافظه پنهان برای منابع بارگیری شده توسط بازدیدکنندگان بازگشتی.
- تأخیر رویداد رویدادهای کلیک یا صفحه کلید در یک بازی.
API برای اندازه گیری معیارهای سفارشی
از لحاظ تاریخی، توسعهدهندگان وب APIهای سطح پایین زیادی برای اندازهگیری عملکرد نداشتهاند، و در نتیجه مجبور بودهاند به هک متوسل شوند تا ارزیابی کنند که آیا یک سایت عملکرد خوبی دارد یا خیر.
به عنوان مثال، با اجرای یک حلقه requestAnimationFrame
و محاسبه دلتا بین هر فریم، می توان تعیین کرد که آیا رشته اصلی به دلیل وظایف طولانی مدت جاوا اسکریپت مسدود شده است یا خیر. اگر دلتا به طور قابل توجهی طولانی تر از نرخ فریم نمایشگر باشد، می توانید آن را به عنوان یک کار طولانی گزارش دهید. اگرچه چنین هکهایی توصیه نمیشوند، زیرا در واقع عملکرد خود را تحت تأثیر قرار میدهند (مثلاً با تخلیه باتری).
اولین قانون سنجش عملکرد موثر این است که مطمئن شوید تکنیکهای اندازهگیری عملکرد شما خودشان باعث مشکلات عملکردی نمیشوند. بنابراین برای هر معیار سفارشی که در سایت خود اندازه گیری می کنید، بهتر است در صورت امکان از یکی از API های زیر استفاده کنید.
Performance Observer API
Performance Observer API مکانیزمی است که داده ها را از سایر APIهای عملکردی که در این صفحه مورد بحث قرار گرفته اند جمع آوری و نمایش می دهد. درک آن برای به دست آوردن داده های خوب بسیار مهم است.
میتوانید از PerformanceObserver
برای اشتراک غیرفعال رویدادهای مرتبط با عملکرد استفاده کنید. این به تماسهای API اجازه میدهد در دورههای بیکار فعال شوند، به این معنی که معمولاً در عملکرد صفحه تداخلی ایجاد نمیکنند.
برای ایجاد یک PerformanceObserver
، آن را به عنوان یک تماس ارسال کنید تا هر زمان که ورودیهای عملکرد جدیدی ارسال شد، اجرا شود. سپس به مشاهدهگر میگویید که چه نوع ورودیهایی را با استفاده از متد observe()
گوش کند:
// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
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'});
} catch (e) {
// Do nothing if the browser doesn't support this API.
}
بخشهای زیر تمام انواع ورودیهای موجود برای مشاهده را فهرست میکنند، اما در مرورگرهای جدیدتر، میتوانید انواع ورودیها را از طریق ویژگی Static PerformanceObserver.supportedEntryTypes
بررسی کنید.
ورودی هایی را که قبلاً اتفاق افتاده را مشاهده کنید
بهطور پیشفرض، اشیاء PerformanceObserver
فقط میتوانند ورودیها را در زمان وقوع مشاهده کنند. اگر بخواهید کد تجزیه و تحلیل عملکرد خود را با تنبلی بارگیری کنید تا منابع با اولویت بالاتر را مسدود نکند، می تواند باعث ایجاد مشکل شود.
برای دریافت ورودی های تاریخی (بعد از وقوع آنها)، هنگام فراخوانی observe()
پرچم buffered
را روی true
تنظیم کنید. مرورگر ورودی های تاریخی را از بافر ورود عملکرد خود در اولین باری که PerformanceObserver
شما فراخوانی می شود شامل می شود.
po.observe({
type: 'some-entry-type',
buffered: true,
});
APIهای عملکرد قدیمی که باید از آنها اجتناب کنید
قبل از Performance Observer API، توسعهدهندگان میتوانستند با استفاده از سه روش زیر که روی شی performance
تعریف شدهاند، به ورودیهای عملکرد دسترسی داشته باشند:
در حالی که این APIها هنوز پشتیبانی می شوند، استفاده از آنها توصیه نمی شود زیرا به شما اجازه نمی دهند هنگام ارسال ورودی های جدید به آن گوش دهید. علاوه بر این، بسیاری از APIهای جدید (مانند وظایف طولانی) از طریق شی performance
در معرض نمایش قرار نمی گیرند، آنها فقط از طریق PerformanceObserver
در معرض دید قرار می گیرند.
مگر اینکه شما به طور خاص به سازگاری با اینترنت اکسپلورر نیاز داشته باشید، بهتر است از این روش ها در کد خود اجتناب کنید و در آینده از PerformanceObserver
استفاده کنید.
API زمانبندی کاربر
User Timing API یک 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()
توانایی های مشابهی را به شما می دهند، مزیت استفاده از User Timing API این است که به خوبی با ابزار عملکرد ادغام می شود. برای مثال، Chrome DevTools اندازهگیریهای زمانبندی کاربر را در پانل عملکرد تصویری میکند، و بسیاری از ارائهدهندگان تجزیه و تحلیل نیز بهطور خودکار اندازهگیریهایی را که انجام میدهید ردیابی میکنند و دادههای مدت زمان را به باطن تجزیه و تحلیل خود ارسال میکنند.
برای گزارش اندازهگیریهای زمانبندی کاربر، میتوانید از PerformanceObserver استفاده کنید و برای مشاهده ورودیهای نوع measure
ثبت نام کنید:
// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
// 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});
} catch (e) {
// Do nothing if the browser doesn't support this API.
}
Long Tasks API
Long Tasks API برای دانستن اینکه چه زمانی رشته اصلی مرورگر به اندازه کافی مسدود شده است تا بر نرخ فریم یا تأخیر ورودی تأثیر بگذارد مفید است. API هر کاری که بیش از 50 میلی ثانیه اجرا شود را گزارش می دهد.
هر زمان که نیاز به اجرای کدهای گران قیمت یا بارگیری و اجرای اسکریپت های بزرگ دارید، ردیابی اینکه آیا آن کد رشته اصلی را مسدود می کند مفید است. در واقع، بسیاری از معیارهای سطح بالاتر بر روی خود Long Tasks API ساخته شده اند (مانند Time to Interactive (TTI) و Total Blocking Time (TBT) ).
برای تعیین زمان انجام کارهای طولانی، می توانید از PerformanceObserver استفاده کنید و برای مشاهده ورودی های نوع longtask
ثبت نام کنید:
// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
// 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});
} catch (e) {
// Do nothing if the browser doesn't support this API.
}
Element Timing API
متریک Largest Contentful Paint (LCP) برای دانستن اینکه چه زمانی بزرگترین بلوک تصویر یا متن روی صفحه نمایش داده شده است مفید است، اما در برخی موارد میخواهید زمان رندر یک عنصر متفاوت را اندازهگیری کنید.
برای این موارد، از Element Timing API استفاده کنید. LCP API در واقع بر روی Element Timing API ساخته شده است و گزارش خودکار بزرگترین عنصر محتوا را اضافه می کند، اما شما همچنین می توانید با افزودن صریح مشخصه elementtiming
به آنها و ثبت یک PerformanceObserver برای مشاهده نوع ورود element
، در مورد سایر عناصر نیز گزارش دهید. .
<img elementtiming="hero-image" />
<p elementtiming="important-paragraph">This is text I care about.</p>
<!-- ... -->
<script>
// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
// Create the performance observer.
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});
} catch (e) {
// Do nothing if the browser doesn't support this API.
}
</script>
API زمانبندی رویداد
متریک Interaction to Next Paint (INP) پاسخگویی کلی صفحه را با مشاهده تمام تعاملات کلیک، ضربه و صفحه کلید در طول عمر یک صفحه ارزیابی می کند. INP یک صفحه اغلب تعاملی است که از زمانی که کاربر تعامل را آغاز کرد تا زمانی که مرورگر فریم بعدی را نشان میدهد که نتیجه بصری ورودی کاربر را نشان میدهد، طولانیترین زمان را برای تکمیل آن به طول انجامید.
معیار INP توسط API زمانبندی رویداد ممکن شده است. این API تعدادی مُهر زمانی را که در طول چرخه حیات رویداد رخ میدهند، نشان میدهد، از جمله:
-
startTime
: زمانی که مرورگر رویداد را دریافت می کند. -
processingStart
: زمانی که مرورگر میتواند پردازشگرهای رویداد را برای رویداد آغاز کند. -
processingEnd
: زمانی که مرورگر اجرای تمام کدهای همزمان آغاز شده از کنترل کننده رویداد برای این رویداد را به پایان می رساند. -
duration
: زمان (به دلایل امنیتی به 8 میلی ثانیه گرد شده) بین زمانی که مرورگر رویداد را دریافت می کند تا زمانی که بتواند فریم بعدی را پس از اتمام اجرای همه کدهای همزمان آغاز شده از کنترل کننده رویداد نقاشی کند.
مثال زیر نحوه استفاده از این مقادیر را برای ایجاد اندازه گیری های سفارشی نشان می دهد:
// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
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 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 time (ms): ${processingTime}`);
console.log(`Total event duration (ms): ${duration}`);
console.log(`Event type: ${eventType}`);
console.log(target);
});
});
// A durationThreshold of 16ms is necessary to surface more
// interactions, since the default is 104ms. The minimum
// durationThreshold is 16ms.
po.observe({type: 'event', buffered: true, durationThreshold: 16});
} catch (error) {
// Do nothing if the browser doesn't support this API.
}
Resource Timeming API
Resource Timing API به توسعه دهندگان بینش دقیقی درباره نحوه بارگیری منابع برای یک صفحه خاص می دهد. با وجود نام API، اطلاعاتی که ارائه می دهد فقط به داده های زمان بندی محدود نمی شود (اگرچه تعداد زیادی از آن وجود دارد). سایر داده هایی که می توانید به آنها دسترسی داشته باشید عبارتند از:
-
initiatorType
: نحوه واکشی منبع: مانند تگ<script>
یا<link>
یا از یک فراخوانیfetch()
. -
nextHopProtocol
: پروتکل مورد استفاده برای واکشی منبع، مانندh2
یاquic
. -
encodedBodySize
/ decodedBodySize ]: اندازه منبع به شکل رمزگذاری شده یا رمزگشایی شده آن (به ترتیب) -
transferSize
: اندازه منبعی که در واقع از طریق شبکه منتقل شده است. هنگامی که منابع توسط حافظه پنهان تکمیل می شوند، این مقدار می تواند بسیار کوچکتر ازencodedBodySize
باشد، و در برخی موارد می تواند صفر باشد (اگر نیازی به اعتبار سنجی مجدد حافظه پنهان نباشد).
میتوانید از ویژگی transferSize
ورودیهای زمانبندی منبع برای اندازهگیری متریک نرخ ضربه حافظه پنهان یا متریک اندازه کل منبع ذخیرهشده استفاده کنید، که میتواند برای درک اینکه چگونه استراتژی ذخیرهسازی منابع شما بر عملکرد بازدیدکنندگان تکراری تأثیر میگذارد، مفید باشد.
مثال زیر تمام منابع درخواست شده توسط صفحه را ثبت می کند و نشان می دهد که آیا هر منبع توسط کش تکمیل شده است یا خیر.
// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// If transferSize is 0, the resource was fulfilled via the cache.
console.log(entry.name, entry.transferSize === 0);
}
});
// Start listening for `resource` entries to be dispatched.
po.observe({type: 'resource', buffered: true});
} catch (e) {
// Do nothing if the browser doesn't support this API.
}
Navigation Timing API
Navigation Timing API شبیه به Resource Timing API است، اما فقط درخواستهای ناوبری را گزارش میکند. نوع ورودی navigation
نیز مشابه نوع ورودی resource
است، اما حاوی برخی اطلاعات اضافی است که فقط مربوط به درخواست های ناوبری است (مانند زمانی که DOMContentLoaded
و رویدادهای load
فعال می شوند).
یکی از معیارهایی که بسیاری از توسعهدهندگان برای درک زمان پاسخ سرور دنبال میکنند ( زمان تا اولین بایت (TTFB) ) با استفاده از Navigation Timing API در دسترس است—مخصوصاً مهر زمانی responseStart
ورودی است.
// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// If transferSize is 0, the resource was fulfilled via the cache.
console.log('Time to first byte', entry.responseStart);
}
});
// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});
} catch (e) {
// Do nothing if the browser doesn't support this API.
}
یکی دیگر از توسعه دهندگان متریک که ممکن است به آن اهمیت دهند، زمان راه اندازی سرویس دهنده برای درخواست های ناوبری است. این مدت زمانی است که مرورگر برای راهاندازی رشته سرویسکار قبل از اینکه بتواند رویدادهای واکشی را رهگیری کند، طول میکشد.
زمان راهاندازی کارگر سرویس برای یک درخواست ناوبری خاص را میتوان از دلتای بین entry.responseStart
و entry.workerStart
تعیین کرد.
// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
// 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});
} catch (e) {
// Do nothing if the browser doesn't support this API.
}
Server Timing API
Server Timing API به شما امکان می دهد داده های زمان بندی درخواستی خاص را از سرور خود به مرورگر از طریق سرصفحه های پاسخ ارسال کنید. به عنوان مثال، می توانید مشخص کنید که جستجوی داده ها در یک پایگاه داده برای یک درخواست خاص چقدر طول کشیده است - که می تواند در اشکال زدایی مشکلات عملکرد ناشی از کندی سرور مفید باشد.
برای توسعهدهندگانی که از ارائهدهندگان تجزیه و تحلیل شخص ثالث استفاده میکنند، Server Timing API تنها راه ارتباط دادههای عملکرد سرور با سایر معیارهای تجاری است که این ابزارهای تحلیلی ممکن است اندازهگیری کنند.
برای مشخص کردن دادههای زمانبندی سرور در پاسخهای خود، میتوانید از هدر پاسخ Server-Timing
استفاده کنید. در اینجا یک مثال است.
HTTP/1.1 200 OK
Server-Timing: miss, db;dur=53, app;dur=47.2
سپس، از صفحات خود، میتوانید این دادهها را هم در ورودیهای resource
یا navigation
از APIهای Resource Timeming و Navigation Timing بخوانید.
// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
// 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});
} catch (e) {
// Do nothing if the browser doesn't support this API.
}