Pelajari cara menggunakan API ini untuk mengukur kinerja aplikasi Anda
Browser DevTools sangat bagus untuk memantau kinerja aplikasi web di PC pengembangan lokal Anda. Namun, cara ini kurang praktis untuk mengukur kecepatan situs di berbagai perangkat, browser, dan koneksi jaringan di seluruh lokasi global.
Performance API mencatat metrik seperti DevTool dari pengguna sebenarnya saat mereka menavigasi aplikasi Anda. Anda dapat memposting data yang dikumpulkan ke layanan seperti Asayer.io, mis.
asayer.event('load-performance', { 'os' : 'Ubuntu', 'agent' : 'Firefox 88.0', 'location': 'US', 'pageload': 1522.598, 'paint' : 5969.123, 'ajaxinit': 1507.067 });
Untuk membantu mengidentifikasi hambatan kinerja pada browser, perangkat, atau bahkan sesi pengguna tertentu.
Apa itu API Kinerja?
Performance API adalah kumpulan API yang digunakan untuk mengukur:
Secara historis, pengembang harus mengadopsi fungsi Date()
untuk mencatat waktu yang telah berlalu, misalnya.
const startTime = new Date(); doSomething(); const elapsedTime = new Date() - startTime; console.log(`doSomething() took ${ elapsedTime }ms`);
tetapi Performance API-nya adalah:
- resolusi lebih tinggi. Berbeda dengan
Date()
, ini mencatat waktu dalam sepersekian milidetik. - lebih terpercaya.
Date()
menggunakan waktu sistem sehingga pengaturan waktu menjadi tidak akurat ketika OS menyinkronkan jam.
API tersedia dalam JavaScript sisi klien di sebagian besar browser modern dan dapat dideteksi dengan:
if ('performance' in window) { // use Performance APIs }
Sumber daya dan waktu pengguna juga tersedia di Pekerja Web sisi klien. Ini memberikan cara untuk menjalankan skrip yang berjalan lama atau mahal secara komputasi di latar belakang yang tidak mengganggu thread pemrosesan utama browser.
API pengaturan waktu pengguna juga tersedia di sisi server:
- Aplikasi Node.js dengan modul
performance_hook
, dan - Aplikasi Deno dijalankan dengan opsi
--allow-hrtime
.
Performance API dan dokumentasinya mungkin agak sulit dipahami karena telah berkembang. Saya harap informasi dan contoh dalam artikel ini membantu menggambarkan potensinya.
Memuat properti waktu
Bagian di bawah ini menjelaskan:
- waktu navigasi halaman yang mengembalikan objek
PerformanceNavigationTiming
, dan - resource timings yang mengembalikan objek
PerformanceResourceTiming
Kedua objek menyediakan properti identifikasi berikut:
- nama — URL sumber daya
- entryType — jenis kinerja (
"navigation"
untuk laman,"resource"
untuk aset laman) - initiatorType — sumber daya yang memulai entri kinerja (
"navigation"
untuk laman) - serverTiming — array objek PerformanceServerTiming dengan metrik
name
,description
, danduration
yang ditulis oleh server ke HTTPServer-Timing
header
Kedua objek menyediakan properti pengaturan waktu berikut yang ditampilkan di sini dalam urutan kronologis yang Anda perkirakan akan terjadi. Stempel waktu dalam milidetik relatif terhadap awal pemuatan halaman:
- startTime — stempel waktu saat pengambilan dimulai (
0
untuk laman karena ini adalah aset pertama yang dimuat) - nextHopProtocol — protokol jaringan yang digunakan
- workerStart — stempel waktu sebelum memulai Service Worker Aplikasi Web Progresif (PWA) (
0
jika permintaan tidak dicegat oleh Service Worker) - redirectStart — stempel waktu pengambilan yang memulai pengalihan
- redirectEnd — stempel waktu setelah menerima byte terakhir dari respons pengalihan terakhir
- fetchStart — stempel waktu sebelum sumber daya diambil
- domainLookupStart — stempel waktu sebelum pencarian DNS
- domainLookupEnd — stempel waktu setelah pencarian DNS
- connectStart — stempel waktu sebelum browser membuat koneksi server
- connectEnd — stempel waktu setelah membuat koneksi server
- secureConnectionStart — stempel waktu sebelum browser memulai proses jabat tangan SSL
- requestStart — stempel waktu sebelum browser meminta sumber daya
- responseStart — stempel waktu saat browser menerima byte data pertama
- responseEnd — stempel waktu setelah menerima byte terakhir atau menutup koneksi
- durasi — perbedaan antara startTime dan responseEnd
Kedua objek menyediakan properti ukuran unduhan berikut:
- transferSize — ukuran sumber daya dalam byte (oktet), termasuk header dan isi kompresi
- encodedBodySize — isi muatan sumber daya dalam byte (oktet) sebelum mendekode/membuka kompresi
- decodedBodySize — isi payload sumber daya dalam byte (oktet) setelah decoding/pembukaan kompresi
Objek halaman PerformanceNavigationTiming
memberikan metrik lebih lanjut tentang pemuatan dan peristiwa DOM, meskipun ini tidak didukung di Safari:
- redirectCount — jumlah pengalihan
- unloadEventStart — stempel waktu sebelum peristiwa
unload
pada dokumen sebelumnya (nol jika tidak ada dokumen sebelumnya) - unloadEventEnd — stempel waktu setelah peristiwa
unload
pada dokumen sebelumnya (nol jika tidak ada dokumen sebelumnya) - domInteractive — stempel waktu sebelum browser menyetel kesiapan dokumen ke interaktif ketika penguraian HTML dan konstruksi DOM selesai
- domContentLoadedEventStart — stempel waktu sebelum peristiwa
DOMContentLoaded
dokumen diaktifkan - domContentLoadedEventEnd — stempel waktu setelah acara
DOMContentLoaded
dokumen selesai - domComplete — stempel waktu sebelum browser menetapkan kesiapan dokumen untuk selesai ketika konstruksi DOM dan peristiwa
DOMContentLoaded
telah selesai - loadEventStart — stempel waktu sebelum peristiwa laman
load
diaktifkan - loadEventEnd — stempel waktu setelah peristiwa laman
load
dan semua aset tersedia
Waktu navigasi
Navigation Timing API menyusun waktu untuk membongkar halaman sebelumnya, pengalihan, pencarian DNS, pemuatan halaman, ukuran file, peristiwa pemuatan, dan banyak lagi. Informasi tersebut akan sulit ditentukan secara andal dengan cara lain apa pun.
Pengaturan waktu navigasi tersedia untuk jendela JavaScript sisi klien dan fungsi Web Worker. Berikan tipe "navigation"
ke performance.getEntriesByType()
:
const pageTiming = performance.getEntriesByType('navigation');
atau URL halaman ke performance.getEntriesByName()
:
const pageTiming = performance.getEntriesByName(window.location);
Opsi mana pun akan mengembalikan array dengan elemen tunggal yang berisi objek PerformanceNavigationTiming
(lihat properti waktu muat). Ini berisi properti read-only tentang waktu pemuatan sumber daya, mis.
{ connectEnd: 139 connectStart: 103 decodedBodySize: 72325 domComplete: 771 domContentLoadedEventEnd: 634 domContentLoadedEventStart: 630 domInteractive: 421 domainLookupEnd: 103 domainLookupStart: 87 duration: 771 encodedBodySize: 13091 entryType: "navigation" fetchStart: 0 initiatorType: "navigation" loadEventEnd: 771 loadEventStart: 771 name: "https://domain.com/" nextHopProtocol: "h2" redirectCount: 0 redirectEnd: 0 redirectStart: 0 requestStart: 140 responseEnd: 154 responseStart: 154 secureConnectionStart: 115 serverTiming: Array [] startTime: 0 transferSize: 13735 type: "reload" unloadEventEnd: 171 unloadEventStart: 169 workerStart: 0 }
Anda dapat menggunakannya untuk menghitung metrik pemuatan halaman yang berguna dari pengguna, misalnya.
if ('performance' in window) { const pageTiming = performance.getEntriesByName(window.location)[0], pageDownload = pageTiming.duration, pageDomReady = pageTiming.domContentLoadedEventStart, pageFullyReady = pageTiming.loadEventEnd; }
Waktu sumber daya
Anda dapat memeriksa waktu pemuatan untuk sumber daya lain seperti gambar, stylesheet, skrip, Fetch, dan XMLHttpRequest panggilan Ajax dengan cara yang mirip dengan halaman.
Pengaturan waktu sumber daya tersedia untuk jendela JavaScript sisi klien dan fungsi Web Worker. Berikan tipe "resource"
ke performance.getEntriesByType()
untuk mengembalikan array. Setiap elemen adalah objek PerformanceResourceTiming
(lihat properti waktu muat) yang mewakili sumber daya yang dimuat oleh halaman (tetapi bukan halaman itu sendiri):
const resourceTiming = performance.getEntriesByType('resource');
contoh hasil:
[ { name: "https://domain.com/script1.js", entryType: "resource", initiatorType: "script", fetchStart: 102, duration: 51 ...etc... }, { name: "https://domain.com/style1.css", entryType: "resource", initiatorType: "link", fetchStart: 323, duration: 54 ...etc... }, { name: "https://domain.com/service/", entryType: "resource", initiatorType: "xmlhttprequest", fetchStart: 598, duration: 30 ...etc... }, ...etc... ]
Anda juga dapat mengambil sumber daya dengan meneruskan URL tepat ke performance.getEntriesByName()
:
const resourceTiming = performance.getEntriesByName('https://domain.com/style1.css');
Ini mengembalikan array dengan satu elemen:
[ { name: "https://domain.com/style1.css", entryType: "resource", initiatorType: "link", fetchStart: 323, duration: 54 ...etc... } ]
Anda dapat menggunakan ini untuk melaporkan guna menghitung waktu muat dan ukuran setiap sumber daya JavaScript serta totalnya:
if ('performance' in window) { // total size of all JavaScript files let scriptTotalSize = 0; // array of script names, load times, and uncompressed file sizes const script = performance.getEntriesByType('resource') .filter( r => r.initiatorType === 'script') .map( r => { let size = r.decodedBodySize; scriptTotalSize += size; return { name: r.name, load: r.duration, size }; }); }
Performance API mencatat setidaknya 150 metrik sumber daya, namun Anda dapat menentukan nomor tertentu dengan performance.setResourceTimingBufferSize(N)
, misalnya.
// record metrics for 300 page resources performance.setResourceTimingBufferSize(300);
Anda dapat menghapus metrik yang ada dengan performance.clearResourceTimings()
. Ini mungkin praktis ketika Anda tidak lagi memerlukan informasi sumber daya halaman tetapi ingin mencatat permintaan Ajax:
// clear timings performance.clearResourceTimings(); // API Fetch request const res = await Fetch('/service1/'); // one resource returned const resourceTiming = performance.getEntriesByType('resource');
Waktu pengecatan
Paint Timing API tersedia untuk fungsi jendela JavaScript sisi klien dan mencatat dua operasi rendering yang diamati selama konstruksi halaman.
Berikan tipe "paint"
ke performance.getEntriesByType()
untuk mengembalikan array yang berisi dua objek PerformancePaintTiming:
const paintTiming = performance.getEntriesByType('paint');
Hasil:
[ { "name": "first-paint", "entryType": "paint", "startTime": 242, "duration": 0 }, { "name": "first-contentful-paint", "entryType": "paint", "startTime": 243, "duration": 0 } ]
Di mana:
- first-paint: browser telah melukis piksel pertama pada laman, dan
- first-contentful-paint: browser telah mengecat item pertama konten DOM, seperti teks atau gambar.
Perhatikan bahwa "duration"
akan selalu nol.
kinerja.sekarang()
performance.now()
mengembalikan stempel waktu resolusi tinggi dalam sepersekian milidetik sejak awal masa proses. Metode ini tersedia di JavaScript sisi klien, Pekerja Web, Node.js, dan Deno.
Di JavaScript sisi klien, pengatur waktu performance.now()
dimulai dari nol ketika proses yang bertanggung jawab untuk membuat document
dimulai. Timer Web Worker, Node.js, dan Deno dimulai saat proses skrip pertama kali dijalankan.
Perhatikan bahwa skrip Node.js harus memuat Modul Performance hooks (perf_hooks
) untuk menggunakan Performance API. Di CommonJS:
const { performance } = require('perf_hooks');
atau sebagai modul ES:
import { performance } from 'perf_hooks';
Anda dapat menggunakan performance.now()
untuk skrip waktu, mis.
const doSomethingStart = performance.now(); doSomething(); const doSomethingElapsed = performance.now() - doSomethingStart;
"PropertitimeOrigin
" non-standar selanjutnya mengembalikan stempel waktu saat proses saat ini dimulai. Ini diukur dalam waktu Unix sejak 1 Januari 1970 dan tersedia di Node.js dan browser JavaScript (bukan IE atau Safari):
Waktu pengguna
performance.now()
menjadi rumit saat melakukan lebih dari beberapa pengukuran waktu. Metode "performance.mark()
" menambahkan objek bernama "Objek PerformanceMark" dengan stempel waktu ke buffer kinerja. Ini tersedia di JavaScript sisi klien, Pekerja Web, Node.js, dan Deno:
// Node.js scripts require: // CommonJS: const { performance } = require('perf_hooks'); // or ESM : import { performance } from 'perf_hooks'; performance.mark('script:start'); performance.mark('doSomething1:start'); doSomething1(); performance.mark('doSomething1:end'); performance.mark('doSomething2:start'); doSomething2(); performance.mark('doSomething2:end'); performance.mark('script:end');
Berikan tipe "mark"
ke performance.getEntriesByType()
untuk mengembalikan serangkaian tanda:
const userTiming = performance.getEntriesByType('mark');
Array yang dihasilkan berisi objek dengan properti name
dan startTime
:
[ { detail: null duration: 0 entryType: "mark" name: "script:start" startTime: 100 }, { detail: null duration: 0 entryType: "mark" name: "doSomething1:start" startTime: 100 }, { detail: null duration: 0 entryType: "mark" name: "doSomething1:end" startTime: 123 }, ...etc... ]
Metode performance.measure()
menghitung waktu yang berlalu antara dua tanda. Itu melewati nama ukuran, nama tanda awal (atau nilai palsu untuk menggunakan waktu buka halaman/skrip), dan nama tanda akhir (atau nilai palsu untuk menggunakan waktu saat ini), misalnya.
performance.measure('doSomething1', 'doSomething1:start', 'doSomething1:end'); performance.measure('script', null, 'doSomething1:end');
Ini menambahkan objek PerformanceMeasure ke buffer kinerja dengan durasi yang dihitung. Berikan tipe "measure"
ke performance.getEntriesByType()
untuk mengembalikan serangkaian ukuran:
const userTiming = performance.getEntriesByType('measure');
Array yang dihasilkan:
[ { detail: null duration: 211 entryType: "measure" name: "doSomething1" startTime: 100 }, { detail: null duration: 551 entryType: "measure" name: "script" startTime: 100 } ]
Anda juga dapat mengambil entri tanda dan ukur berdasarkan nama menggunakan performance.getEntriesByName()
:
performance.getEntriesByName('doSomething1');
Metode bermanfaat lainnya meliputi:
performance.getEntries()
— mengembalikan serangkaian semua entri kinerja termasuk tanda, ukuran, waktu navigasi, waktu sumber daya, dan waktu pengecatanperformance.clearMarks( [name] )
— menghapus tanda bernama, atau menghilangkan nama untuk menghapus semua tandaperformance.clearMeasures( [name] )
— menghapus ukuran yang disebutkan, atau menghilangkan nama untuk menghapus semua ukuran
Pemantauan Bagian Depan
Asayer adalah alat pemantauan frontend yang memutar ulang semua yang dilakukan pengguna Anda dan menunjukkan bagaimana aplikasi web Anda berperilaku untuk setiap masalah. Ini memungkinkan Anda mereproduksi masalah, menggabungkan kesalahan JS, dan memantau kinerja aplikasi web Anda.
Selamat melakukan debug, untuk tim frontend modern — Mulai pantau aplikasi web Anda secara gratis.
Pengamat Kinerja
Antarmuka PerformanceObserver dapat melihat perubahan pada buffer kinerja dan menjalankan fungsi ketika objek tertentu muncul. Ini paling praktis digunakan untuk peristiwa penandaan, pengukuran, dan pemuatan sumber daya (waktu navigasi dan pengecatan umumnya akan terjadi sebelum skrip dimulai).
Pertama, tentukan fungsi pengamat. Ini dapat mencatat peristiwa atau memposting data ke titik akhir statistik:
function performanceObserver(list, observer) { list.getEntries().forEach(entry => { console.log('---'); console.log(`name : ${ entry.name }`); console.log(`type : ${ entry.type }`); console.log(`start : ${ entry.startTime }`); console.log(`duration: ${ entry.duration }`); }); }
Fungsi tersebut memiliki parameter berikut:
Lewati fungsi ini saat membuat objek PerformanceObserver
baru lalu jalankan metodeobserve()
dengan entryTypes
untuk mengamati:
Menambahkan tanda atau ukuran baru sekarang akan menjalankan fungsi performanceObserver()
dan menampilkan detail tentang pengukuran tersebut.
Opsi kinerja masa depan
Browser berbasis Chrome menawarkan performance.memory
property non-standar yang mengembalikan satu objek MemoryInfo:
Di mana:
- jsHeapSizeLimit — ukuran maksimum heap dalam byte
- totalJSHeapSize — total ukuran heap yang dialokasikan dalam byte, dan
- usedJSHeapSize — Segmen tumpukan JS yang sedang aktif dalam byte.
Frame timing API tidak diterapkan di browser apa pun, tetapi akan mencatat jumlah kerja browser dalam satu iterasi loop peristiwa. Hal ini mencakup pemrosesan peristiwa DOM, animasi CSS, rendering, pengguliran, pengubahan ukuran, dll. API harus dapat melaporkan potensi gangguan ketika sebuah frame memerlukan waktu lebih dari 16,7 milidetik sehingga pembaruan turun di bawah 60 frame per detik.
Terakhir, “API Profil Mandiri” adalah “fitur eksperimental yang sedang dikembangkan di Chrome”. Mengingat tingkat sampel, API akan membantu menemukan kode yang lambat atau tidak diperlukan dengan cara yang mirip dengan laporan kinerja DevTools:
// define a new profiler with 10ms sample rate const profile = await performance.profile({ sampleInterval: 10 }); // run code doSomething(); // stop the profiler and capture a trace const trace = await profile.stop();
Temukan masalah kinerja
Sangat mudah untuk berasumsi bahwa aplikasi Anda berjalan dengan baik ketika Anda mengembangkannya di PC baru yang terhubung ke jaringan cepat. Performance API menawarkan cara untuk membuktikan — atau menyangkal — masalah performa dengan mengumpulkan metrik pengguna sebenarnya berdasarkan perangkat, koneksi, dan lokasi mereka.
Awalnya diterbitkan di https://blog.asayer.io pada 12 Mei 2021.