Progresywne aplikacje internetowe umożliwiają deweloperom tworzenie nowej klasy aplikacji, które zapewniają niezawodne i wysoko wydajne wrażenia użytkownika. Aby jednak mieć pewność, że aplikacja internetowa osiąga pożądaną skuteczność, deweloperzy muszą mieć dostęp do danych o wydajności w wysokiej rozdzielczości. Specyfikacja W3C dotycząca osi czasu wydajności definiuje interfejs dla przeglądarek, który zapewnia programowy dostęp do niskiego poziomu danych o czasie. Otwiera to drogę do ciekawych zastosowań:
- offline i niestandardowa analiza skuteczności
- zewnętrzne narzędzia do analizy i wizualizacji skuteczności
- oceny skuteczności zintegrowane z IDE i innymi narzędziami dla programistów
Dostęp do tego rodzaju danych jest już dostępny w większości popularnych przeglądarek w przypadku czasu nawigacji, czasu zasobów i czasu użytkownika. Najnowszym dodatkiem jest interfejs performance observer, który jest w podstawie interfejsem strumieniowym do asynchronicznego zbierania informacji o czasie opóźnienia na niskim poziomie, ponieważ jest on zbierany przez przeglądarkę. Ten nowy interfejs oferuje wiele ważnych zalet w porównaniu z wcześniejszymi metodami uzyskiwania dostępu do osi czasu:
- Obecnie aplikacje muszą okresowo sprawdzać i porównywać zapisane pomiary, co jest kosztowne. Ten interfejs umożliwia im zamawianie oddzwonów. (In other words, there is no need to poll). Dzięki temu aplikacje korzystające z tego interfejsu API mogą być bardziej responsywne i skuteczne.
- Nie podlega on ograniczeniom bufora (domyślnie większość buforów ma 150 elementów) i unika sytuacji wyścigu między różnymi konsumentami, którzy mogą chcieć zmodyfikować bufor.
- Powiadomienia dotyczące monitorowania wydajności są dostarczane asynchronicznie, a przeglądarka może wysyłać je w czasie bezczynności, aby nie konkurowały z procesem renderowania.
Od wersji 52 przeglądarki Chrome interfejs monitorowania wydajności jest domyślnie włączony. Zobaczmy, jak z niego korzystać.
<html>
<head>
<script>
var observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => {
// Display each reported measurement on console
if (console) {
console.log("Name: " + entry.name +
", Type: " + entry.entryType +
", Start: " + entry.startTime +
", Duration: " + entry.duration + "\n");
}
})
});
observer.observe({entryTypes: ['resource', 'mark', 'measure']});
performance.mark('registered-observer');
function clicked(elem) {
performance.measure('button clicked');
}
</script>
</head>
<body>
<button onclick="clicked(this)">Measure</button>
</body>
</html>
Ta prosta strona zaczyna się od tagu skryptu definiującego kod JavaScript:
- Tworzymy instancję nowego obiektu
PerformanceObserver
i przekazujemy konstruktorowi obiektu funkcję obsługi zdarzenia. Konstruktor inicjuje obiekt tak, aby nasz moduł obsługi był wywoływany za każdym razem, gdy nowy zbiór danych pomiarowych będzie gotowy do przetworzenia (dane pomiarowe są przekazywane jako lista obiektów). Moduł obsługi jest tu zdefiniowany jako anonimowa funkcja, która po prostu wyświetla sformatowane dane pomiarowe w konsoli. W praktyce dane te mogą być przechowywane w chmurze na potrzeby późniejszej analizy lub przekazywane do interaktywnego narzędzia do wizualizacji. - Za pomocą metody
observe()
rejestrujemy typy zdarzeń związanych z czasowaniem, które nas interesują, a następnie wywołujemy metodęmark()
, aby oznaczyć moment rejestracji, który uznamy za początek naszych przedziałów czasowych. - Definiujemy element obsługi kliknięcia dla przycisku zdefiniowanego w sekcji treści strony. Ten handler kliknięcia wywołuje metodę
measure()
, aby zarejestrować dane o czasie kliknięcia przycisku.
W treści strony definiujemy przycisk, przypisujemy do niego moduł obsługi kliknięcia do zdarzenia onclick
i gotowe.
Jeśli teraz załadujemy stronę i otwieramy panel Narzędzi deweloperskich w Chrome, aby obserwować konsolę JavaScript, to za każdym razem, gdy klikniemy przycisk, zostanie przeprowadzony pomiar wydajności. Ponieważ zarejestrowaliśmy się do obserwowania takich pomiarów, są one przesyłane do naszego przetwarzacza zdarzeń asynchronicznie bez potrzeby sprawdzania linii czasu, która wyświetla pomiary w konsoli w miarę ich występowania:
Wartość start
to sygnatura czasowa początkowa zdarzeń typu mark
(ta aplikacja ma tylko jedno takie zdarzenie). Zdarzenia typu measure
nie mają określonego czasu rozpoczęcia. Przedstawiają pomiary czasu wykonane względem ostatniego zdarzenia typu mark
. W związku z tym wartości czasu widoczne tutaj reprezentują upływ czasu między wywołaniem funkcji mark()
, która służy jako wspólny punkt początkowy dla interwału, a wielokrotnymi kolejnymi wywołaniami funkcji measure()
.
Jak widzisz, ten interfejs API jest dość prosty i umożliwia zbieranie danych o wydajności w czasie rzeczywistym z wysoką rozdzielczością i bez pollingu. Powinien on ułatwić tworzenie wydajniejszych narzędzi do analizy wydajności aplikacji internetowych.