Obserwator wydajności – skuteczny dostęp do danych o skuteczności

Progresywne aplikacje internetowe umożliwiają programistom tworzenie nowej klasy aplikacji, które zapewniają użytkownikom niezawodne i wydajne funkcje. Aby jednak mieć pewność, że aplikacja internetowa osiąga oczekiwane cele związane z wydajnością, deweloperzy muszą mieć dostęp do danych z pomiarów wydajności w wysokiej rozdzielczości. Specyfikacja osi czasu wydajności W3C definiuje interfejs dla przeglądarek, który zapewnia programowy dostęp do danych o niskim czasie. Otworzy się kilka ciekawych przypadków użycia:

  • analizy skuteczności offline i niestandardowej
  • narzędzia firm zewnętrznych 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 o czasie jest już możliwy w większości popularnych przeglądarek w zakresie czasu nawigacji, czasu działania zasobów i czasu działania użytkownika. Najnowszym dodatkiem jest interfejs obserwatora wydajności, który zasadniczo służy do asynchronicznego gromadzenia informacji o niskim czasie w miarę ich zbierania przez przeglądarkę. Nowy interfejs ma szereg zalet w porównaniu z poprzednimi metodami dostępu do osi czasu:

  • Obecnie aplikacje muszą okresowo sondować i różnicować zapisane pomiary, co jest kosztowne. Ten interfejs umożliwia oddzwonienie. (Innymi słowy, nie ma potrzeby przeprowadzania ankiet). W efekcie aplikacje używające tego interfejsu mogą być bardziej elastyczne i wydajniejsze.
  • Nie podlega on limitom bufora (większość z buforów jest domyślnie ustawianych na 150 elementów) i uniknie konkurencyjności między różnymi klientami, którzy mogliby chcieć zmodyfikować bufor.
  • Powiadomienia obserwatora wydajności są dostarczane asynchronicznie, a przeglądarka może je wysyłać w czasie bezczynności, aby uniknąć konkurowania z krytycznymi działaniami związanymi z renderowaniem.

Od 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 instancję nowego obiektu PerformanceObserver i przekazujemy funkcję obsługi zdarzeń do konstruktora obiektów. Konstruktor inicjuje obiekt w taki sposób, że będzie 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 funkcja anonimowa, która po prostu wyświetla w konsoli sformatowane dane pomiarowe. W rzeczywistości dane te mogą być przechowywane w chmurze do późniejszej analizy lub przekazane do interaktywnego narzędzia do wizualizacji.
  • Rejestrujemy się na interesujące nas typy zdarzeń czasowych za pomocą metody observe() i wywołujemy metodę mark(), aby wskazać moment rejestracji, który uwzględnia początek interwałów czasowych.
  • Definiujemy moduł obsługi kliknięcia dla przycisku zdefiniowanego w treści strony. Wywołuje on metodę measure(), aby rejestrować dane o czasie kliknięcia przycisku.

W treści strony definiujemy przycisk i przypisujemy moduł obsługi kliknięcia do zdarzenia onclick – i gotowe!

Jeśli wczytamy stronę i otworzymy panel Narzędzi deweloperskich w Chrome, aby obserwować konsolę JavaScript, po każdym kliknięciu przycisku zostanie przeprowadzony pomiar wydajności. Ponieważ zarejestrowaliśmy się w celu obserwacji takich pomiarów, są one przesyłane asynchronicznie do naszego modułu obsługi zdarzeń bez konieczności pobierania osi czasu, która wyświetla aktualne pomiary w konsoli:

Obserwator wydajności.

Wartość start reprezentuje sygnaturę czasową rozpoczęcia zdarzeń typu mark (z których ta aplikacja ma tylko jedno). Zdarzenia typu measure nie mają ustalonego czasu rozpoczęcia. Reprezentują pomiary czasu dokonane w odniesieniu do ostatniego zdarzenia mark. W tym miejscu widoczne wartości czasu trwania odpowiadają czasowi, który upływa między wywołaniem funkcji mark(), która jest punktem początkowym przedziału czasu i wieloma 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 odpytywania, co powinno otworzyć możliwości wydajniejszego narzędzia do pracy z aplikacjami internetowymi.