Informacje o aplikacji internetowej
Wysoka wydajność aplikacji internetowych ma kluczowe znaczenie dla wygody użytkowników. W miarę jak aplikacje internetowe stają się coraz bardziej złożone, zrozumienie wpływu na wydajność jest kluczowe dla tworzenia atrakcyjnych wrażeń. W ciągu ostatnich kilku lat w przeglądarce pojawiło się wiele różnych interfejsów API, które pomagają analizować wydajność sieci, czas wczytywania itp. Nie zawsze jednak zapewniają one wystarczająco szczegółowe informacje i elastyczność, aby można było znaleźć przyczynę spowolnienia aplikacji. Wprowadź interfejs User Timing API, który udostępnia mechanizm umożliwiający instrumentację aplikacji internetowej w celu określenia, na co aplikacja poświęca czas. W tym artykule omówimy interfejs API i podamy przykłady jego użycia.
Nie można optymalizować tego, czego nie da się zmierzyć
Pierwszym krokiem do przyspieszenia wolnej aplikacji internetowej jest ustalenie, gdzie marnuje się czas. Pomiar wpływu fragmentów kodu JavaScript na czas to idealny sposób na zidentyfikowanie punktów zapalnych, co jest pierwszym krokiem do znalezienia sposobu na poprawę wydajności. Na szczęście interfejs API User Timing umożliwia wstawianie wywołań interfejsu API w różnych częściach kodu JavaScript, a następnie wyodrębnianie szczegółowych danych o czasie działań użytkownika, które można wykorzystać do optymalizacji.
Czas w wysokiej rozdzielczości i now()
Podstawowym elementem dokładnego pomiaru czasu jest precyzja. Kiedyś pomiary czasu były oparte na milisekundach, co jest w porządku, ale stworzenie strony działającej płynnie w 60 klatkach na sekundę oznacza, że każda klatka musi być renderowana w ciągu 16 ms. Jeśli więc masz dokładność tylko do milisekundy, brakuje precyzji potrzebnej do przeprowadzenia dobrej analizy. Wprowadź High Resolution Time, nowy typ pomiaru czasu wbudowany w nowoczesne przeglądarki. High Resolution Time zapewnia sygnatury czasowe w reprezentacji zmiennoprzecinkowej, które mogą być dokładne do mikrosekundy – tysiąc razy lepiej niż wcześniej.
Aby uzyskać bieżący czas w aplikacji internetowej, wywołaj metodę now(), która stanowi rozszerzenie interfejsu Performance. Poniższy kod pokazuje, jak to zrobić:
var myTime = window.performance.now();
Istnieje inny interfejs o nazwie PerformanceTiming, który podaje różne czasy związane z ładowaniem aplikacji internetowej. Metoda now() zwraca czas, który upłynął od momentu navigationStart w PerformanceTiming.
Typ DOMHighResTimeStamp
W przeszłości do mierzenia czasu w aplikacjach internetowych używano np. Date.now(), który zwraca DOMTimeStamp. DOMTimeStamp zwraca liczbę całkowitą milisekund jako wartość. Aby zapewnić większą dokładność wymaganą w przypadku czasu o wysokiej rozdzielczości, wprowadzono nowy typ o nazwie DOMHighResTimeStamp. Ten typ to wartość zmiennoprzecinkowa, która zwraca też czas w milisekundach. Ponieważ jest to reprezentacja zmiennoprzecinkowa, wartość może reprezentować ułamkowe milisekundy, co pozwala uzyskać dokładność do jednej tysięcznej milisekundy.
Interfejs czasu działań użytkownika
Mamy już sygnatury czasowe o wysokiej rozdzielczości, więc użyjmy interfejsu Czas działań użytkownika, aby wyodrębnić informacje o czasie.
Interfejs Czas działań użytkownika udostępnia funkcje, które pozwalają nam wywoływać metody w różnych miejscach w aplikacji. Mogą one tworzyć ścieżkę nawigacyjną w stylu Jasia i Małgosi, która pozwala nam śledzić, na co jest poświęcany czas.
Jak korzystać z aplikacji mark()
Metoda mark() to główne narzędzie w naszym zestawie narzędzi do analizy czasu. mark() przechowuje dla nas sygnaturę czasową. Bardzo przydatną funkcją mark() jest możliwość nadania nazwy sygnaturze czasowej, dzięki czemu interfejs API zapamięta nazwę i sygnaturę czasową jako jedną jednostkę.
Wywołanie metody mark() w różnych miejscach aplikacji pozwala określić, ile czasu zajęło osiągnięcie danego „znacznika” w aplikacji internetowej.
Specyfikacja zawiera szereg sugerowanych nazw znaczników, które mogą być interesujące i są dość zrozumiałe, np. mark_fully_loaded, mark_fully_visible, mark_above_the_fold itp.
Możemy na przykład ustawić znacznik, który będzie wskazywał, kiedy aplikacja jest w pełni załadowana, używając tego kodu:
window.performance.mark('mark_fully_loaded');
Ustawiając nazwane znaczniki w aplikacji internetowej, możemy zebrać wiele danych o czasie i przeanalizować je w wolnej chwili, aby dowiedzieć się, co i kiedy robi aplikacja.
Obliczanie pomiarów za pomocą measure()
Po ustawieniu kilku znaczników czasu możesz sprawdzić, ile czasu upłynęło między nimi. Aby to zrobić, użyj metody measure().
Metoda measure() oblicza czas, który upłynął między znacznikami, a także może mierzyć czas między znacznikiem a dowolną z dobrze znanych nazw zdarzeń w interfejsie PerformanceTiming.
Możesz na przykład obliczyć czas od zakończenia ładowania DOM do pełnego załadowania stanu aplikacji, używając kodu takiego jak:
window.performance.measure('measure_load_from_dom', 'domComplete', 'mark_fully_loaded');
Gdy wywołasz funkcję measure(), zapisze ona wynik niezależnie od ustawionych znaczników, dzięki czemu będzie można go później pobrać. Dzięki zapisywaniu czasów podczas działania aplikacji pozostaje ona responsywna, a po zakończeniu pracy możesz zrzucić wszystkie dane, aby później je przeanalizować.
Odrzucam oceny z: clearMarks()
Czasami przydaje się możliwość pozbycia się wielu ustawionych znaczników. Możesz na przykład wykonywać uruchomienia wsadowe w aplikacji internetowej i chcesz, aby każde uruchomienie było wykonywane od nowa.
Aby usunąć ustawione znaczniki, wystarczy wywołać metodę clearMarks().
Przykładowy kod poniżej usunie wszystkie istniejące znaczniki, dzięki czemu możesz ponownie skonfigurować pomiar czasu, jeśli chcesz.
window.performance.clearMarks();
Oczywiście w niektórych sytuacjach możesz nie chcieć usuwać wszystkich znaczników. Jeśli chcesz pozbyć się konkretnych znaczników, możesz po prostu przekazać nazwę znacznika, który chcesz usunąć. Na przykład ten kod:
window.performance.clearMarks('mark_fully_loaded');
usuwa znacznik ustawiony w pierwszym przykładzie, pozostawiając inne znaczniki bez zmian.
Możesz też usunąć wszystkie wykonane pomiary. Służy do tego metoda clearMeasures(). Działa dokładnie tak samo jak clearMarks(), ale na wszystkich wykonanych pomiarach. Na przykład kod:
window.performance.clearMeasures('measure_load_from_dom');
usunie pomiar wykonany w powyższym przykładzie measure(). Jeśli chcesz usunąć wszystkie pomiary, działa to tak samo jak clearMarks() – wystarczy wywołać clearMeasures() bez argumentów.
Pobieranie danych o czasie
Ustawianie znaczników i mierzenie interwałów jest bardzo przydatne, ale w pewnym momencie chcesz uzyskać dostęp do danych o czasie, aby przeprowadzić analizę. To również jest bardzo proste – wystarczy użyć interfejsu PerformanceTimeline.
Na przykład metoda getEntriesByType() pozwala nam uzyskać wszystkie czasy znaczników lub wszystkie czasy pomiarów w postaci listy, dzięki czemu możemy ją przeglądać i analizować dane. Lista jest zwracana w porządku chronologicznym, dzięki czemu możesz zobaczyć znaczniki w kolejności, w jakiej zostały osiągnięte w aplikacji internetowej.
Kod poniżej:
var items = window.performance.getEntriesByType('mark');
zwraca listę wszystkich znaczników, które zostały trafione w naszej aplikacji internetowej, podczas gdy kod:
var items = window.performance.getEntriesByType('measure');
zwraca listę wszystkich wykonanych pomiarów.
Możesz też wyświetlić listę wpisów, używając ich konkretnej nazwy. Na przykład kod:
var items = window.performance.getEntriesByName('mark_fully_loaded');
zwróci listę z jednym elementem zawierającym sygnaturę czasową „mark_fully_loaded” we właściwości startTime.
Pomiar czasu żądania XHR (przykład)
Teraz, gdy mamy już ogólny obraz interfejsu User Timing API, możemy go użyć do analizy czasu trwania wszystkich żądań XMLHttpRequests w naszej aplikacji internetowej.
Najpierw zmodyfikujemy wszystkie żądania send(), aby wywoływały funkcję, która konfiguruje znaczniki. Jednocześnie zmienimy wywołania zwrotne po udanym żądaniu, aby wywoływały funkcję, która ustawia inny znacznik, a następnie generuje pomiar czasu trwania żądania.
Zwykle obiekt XMLHttpRequest wygląda mniej więcej tak:
var myReq = new XMLHttpRequest();
myReq.open('GET', url, true);
myReq.onload = function(e) {
do_something(e.responseText);
}
myReq.send();
W naszym przykładzie dodamy globalny licznik, aby śledzić liczbę żądań, a także używać go do przechowywania miary dla każdego wysłanego żądania. Kod, który to umożliwia, wygląda tak:
var reqCnt = 0;
var myReq = new XMLHttpRequest();
myReq.open('GET', url, true);
myReq.onload = function(e) {
window.performance.mark('mark_end_xhr');
reqCnt++;
window.performance.measure('measure_xhr_' + reqCnt, 'mark_start_xhr', 'mark_end_xhr');
do_something(e.responseText);
}
window.performance.mark('mark_start_xhr');
myReq.send();
Powyższy kod generuje miarę z unikalną wartością nazwy dla każdego wysyłanego żądania XMLHttpRequest. Zakładamy, że żądania są wykonywane sekwencyjnie – kod żądań równoległych musiałby być nieco bardziej złożony, aby obsługiwać żądania, które zwracają wyniki w niewłaściwej kolejności. Pozostawiamy to jako ćwiczenie dla czytelnika.
Gdy aplikacja internetowa wykona kilka żądań, możemy je wszystkie zrzucić do konsoli za pomocą poniższego kodu:
var items = window.performance.getEntriesByType('measure');
for (var i = 0; i < items.length; ++i) {
var req = items[i];
console.log('XHR ' + req.name + ' took ' + req.duration + 'ms');
}
Podsumowanie
Interfejs User Timing API udostępnia wiele świetnych narzędzi, które można zastosować do dowolnego aspektu aplikacji internetowej. Aby zawęzić listę hotspotów w aplikacji, możesz rozmieścić wywołania interfejsu API w aplikacji internetowej i przetworzyć wygenerowane dane o czasie, aby uzyskać jasny obraz tego, na co jest poświęcany czas. Co jednak, jeśli Twoja przeglądarka nie obsługuje tego interfejsu API? Żaden problem – tutaj znajdziesz świetny polyfill, który bardzo dobrze emuluje interfejs API i dobrze współpracuje z webpagetest.org. Na co więc czekasz? Wypróbuj interfejs User Timing API w swoich aplikacjach, aby dowiedzieć się, jak je przyspieszyć. Użytkownicy będą Ci wdzięczni za poprawę komfortu korzystania z aplikacji.