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ą wydajność, deweloperzy muszą mieć dostęp do danych o wydajności o wysokiej rozdzielczości. Specyfikacja W3C dotycząca osi czasu wydajności definiuje taki 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
- ocena wydajności zintegrowana 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. Nowością jest interfejs performance Obserwatorzy wydajności. Jest to interfejs streamingowy służący do asynchronicznego gromadzenia informacji o czasie niskiego poziomu w chwili ich gromadzenia przez przeglądarkę. Ten nowy interfejs oferuje szereg 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 zażądanie oddzwonienia. (Inaczej mówiąc, nie trzeba przeprowadzać ankiet). 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 uniknąć rywalizacji z krytycznymi zadaniami związanymi z renderowaniem.
Od wersji Chrome 52 interfejs obserwatora 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 nowy obiekt
PerformanceObserver
i przekazujemy funkcję obsługi zdarzeń do konstruktora obiektów. Konstruktor inicjuje obiekt w taki sposób, że nasz moduł obsługi jest wywoływany za każdym razem, gdy nowy zbiór danych pomiarowych jest gotowy do przetworzenia (dane pomiarowe są przekazywane w formie listy obiektów). Moduł obsługi jest tu zdefiniowany jako anonimowe 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 przedziału czasowego. - 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, 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; reprezentują pomiary czasu wykonane względem ostatniego zdarzenia 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 przedziału, a wielokrotnymi kolejnymi wywołaniami funkcji measure()
.
Jak widać, ten interfejs API jest dość prosty i umożliwia zbieranie przefiltrowanych danych o wydajności w wysokiej rozdzielczości w czasie rzeczywistym bez ankietowania, co powinno otworzyć się na bardziej efektywne narzędzia zwiększające wydajność w przypadku aplikacji internetowych.