Informacje o aplikacji internetowej
Aplikacje internetowe o wysokiej wydajności są kluczowe dla zapewnienia użytkownikom wygodnej obsługi. Aplikacje internetowe stają się coraz bardziej złożone, dlatego zrozumienie wpływu na wydajność jest kluczowe dla zapewnienia atrakcyjnego działania. W ostatnich latach w przeglądarce pojawiło się wiele różnych interfejsów API, które pomagają analizować wydajność sieci, czasy wczytywania itp., ale niekoniecznie dostarczają one szczegółowych informacji, które umożliwiłyby znalezienie przyczyny spowolnienia działania aplikacji. Użyj interfejsu User Timing API, który zawiera mechanizm umożliwiający instrumentowanie aplikacji internetowej w celu określenia, na co ona przeznacza czas. W tym artykule omówimy interfejs API oraz podamy przykłady jego zastosowania.
Nie możesz optymalizować tego, czego nie możesz mierzyć
Pierwszym krokiem do przyspieszenia działania aplikacji internetowej jest ustalenie, na co jest tracony czas. Pomiar wpływu czasu wykonywania na obszary kodu JavaScriptu to idealny sposób na zidentyfikowanie newralgicznych punktów, co jest pierwszym krokiem na drodze do zwiększenia wydajności. Na szczęście interfejs User Timing API umożliwia wstawianie wywołań interfejsu API w różnych częściach kodu JavaScriptu, a potem wyodrębnianie szczegółowych danych o czasie, które można wykorzystać do optymalizacji.
Czas w wysokiej rozdzielczości i now()
Podstawowym elementem dokładnego pomiaru czasu jest precyzja. Wcześniej korzystaliśmy z synchronizacji opartej na pomiarze w milisekundach, co jest w porządku, ale tworzenie witryny z płynnym odtwarzaniem przy 60 FPS oznacza, że każda klatka musi być wyświetlana w 16 ms. Jeśli więc masz dokładność tylko do milisekund, nie masz wystarczającej dokładności do przeprowadzenia dobrej analizy. Wpisz czas w wysokiej rozdzielczości, czyli nowy typ pomiaru czasu, który jest wbudowany w nowoczesne przeglądarki. Wysoka rozdzielczość czasu zapewnia znaczniki czasu z liczbą zmiennoprzecinkową, które mogą być dokładne do mikrosekundy – tysiąc razy lepiej niż wcześniej.
Aby uzyskać aktualną godzinę w aplikacji internetowej, wywołaj metodę now()
, która stanowi rozszerzenie interfejsu Performance. Poniżej znajdziesz kod, który to umożliwia:
var myTime = window.performance.now();
Istnieje też inny interfejs o nazwie PerformanceTiming, który zawiera kilka różnych czasów związanych z wczytywaniem aplikacji internetowej. Metoda now()
zwraca czas, który upłynął od momentu wystąpienia zdarzenia navigationStart
w ramach PerformanceTiming.
Typ DOMHighResTimeStamp
Wcześniej, aby mierzyć czas w przypadku aplikacji internetowych, używaliśmy funkcji Date.now()
, która zwraca wartość DOMTimeStamp. Funkcja DOMTimeStamp zwraca wartość liczbową w milisekundach. Aby zapewnić większą dokładność potrzebną do czasu o wysokiej rozdzielczości, wprowadzono nowy typ o nazwie DOMHighResTimeStamp. Ten typ to liczba zmiennoprzecinkowa, która zwraca również czas w milisekundach. Ponieważ jest to liczba zmiennoprzecinkowa, wartość może reprezentować ułamki milisekundy, co daje dokładność do tysięcznej części milisekundy.
Interfejs Czas działań użytkownika
Teraz, gdy mamy znaczniki czasu w wysokiej rozdzielczości, użyjemy interfejsu Czas użytkownika, aby wyodrębnić informacje o czasie.
Interfejs User Timing udostępnia funkcje, które umożliwiają wywoływanie metod w różnych miejscach w aplikacji. Może to stanowić ślad niczym okruchy chleba, który pozwala śledzić, na co jest wydawany czas.
Jak korzystać z aplikacji mark()
Metoda mark()
jest głównym narzędziem w naszym zestawie narzędzi do analizy czasu. mark()
przechowuje dla nas sygnaturę czasową. Zaletą interfejsu mark()
jest to, że możemy nadać nazwę sygnaturze czasowej, a interfejs API zapamięta nazwę i sygnaturę czasową jako jedną jednostkę.
Wywoływanie funkcji mark()
w różnych miejscach aplikacji pozwala określić, ile czasu zajęło Ci osiągnięcie tego „punktu kontrolnego” w aplikacji internetowej.
Specyfikacja podaje kilka sugerowanych nazw znaków, które mogą być interesujące i w pewien sposób samowyjaśniające, np. mark_fully_loaded
,mark_fully_visible
, mark_above_the_fold
itp.
Możemy na przykład ustawić znacznik, gdy aplikacja zostanie w pełni załadowana, za pomocą tego kodu:
window.performance.mark('mark_fully_loaded');
Dzięki ustawianiu nazwanych znaczników w naszej aplikacji internetowej możemy zebrać mnóstwo danych o czasie i w dowolnym momencie je analizować, aby dowiedzieć się, co i kiedy robi aplikacja.
Obliczanie pomiarów za pomocą funkcji measure()
Po ustawieniu wielu punktów pomiarowych czasu musisz określić upływający między nimi czas. W tym celu używasz metody measure()
.
Metoda measure()
oblicza upływający czas między znacznikami, a także może mierzyć czas między Twoim znacznikiem a dowolnym dobrze znanym zdarzeniem w interfejsie PerformanceTiming.
Możesz na przykład obliczyć czas od momentu, gdy DOM jest gotowy, do momentu, gdy stan aplikacji jest w pełni załadowany, za pomocą kodu takiego jak:
window.performance.measure('measure_load_from_dom', 'domComplete', 'mark_fully_loaded');
Gdy wywołasz funkcję measure()
, zapisuje ona wynik niezależnie od ustawionych przez Ciebie znaczników, dzięki czemu możesz je później pobrać. Dzięki przechowywaniu czasów podczas działania aplikacji aplikacja pozostaje responsywna, a po zakończeniu pracy możesz wyodrębnić wszystkie dane, aby przeanalizować je później.
Odrzucanie znaków za pomocą clearMarks()
Czasami przydaje się możliwość usunięcia wielu ustawionych przez Ciebie znaczników. Możesz na przykład wykonywać zbiorcze uruchomienia aplikacji internetowej i chcieć zaczynać od nowa po każdym uruchomieniu.
Możesz łatwo usunąć wszystkie ustawione przez siebie oznaczenia, dzwoniąc pod numer clearMarks()
.
Przykładowy kod poniżej spowoduje usunięcie wszystkich istniejących znaczników, aby można było ponownie ustawić czas.
window.performance.clearMarks();
Oczywiście w niektórych sytuacjach nie chcesz usuwać wszystkich oznaczeń. Jeśli chcesz usunąć określone znaki, możesz przekazać nazwę znaku, który chcesz usunąć. Na przykład kod poniżej:
window.performance.clearMarks('mark_fully_loaded');
usuwa oznaczenie ustawione w pierwszym przykładzie, nie zmieniając innych ustawionych oznaczeń.
Możesz też chcieć pozbyć się wszystkich podjętych działań. W tym celu możesz użyć metody clearMeasures()
. Działa tak samo jak clearMarks()
, ale z tym wyjątkiem, że działa na podstawie wszystkich wykonanych przez Ciebie pomiarów. Na przykład kod:
window.performance.clearMeasures('measure_load_from_dom');
usunie pomiar wykonany w przykładzie measure()
powyżej. Jeśli chcesz usunąć wszystkie miary, wystarczy wywołać funkcję clearMeasures()
bez argumentów.clearMarks()
Pobieranie danych o czasie
Ustalanie punktów i okresów pomiarowych jest bardzo przydatne, ale w pewnym momencie trzeba uzyskać dostęp do danych o czasie, aby przeprowadzić analizę. To też bardzo proste. Wystarczy, że użyjesz interfejsu PerformanceTimeline
.
Na przykład metoda getEntriesByType()
pozwala nam uzyskać wszystkie czasy znaku lub wszystkie czasy pomiaru w postaci listy, dzięki czemu możemy ją przetworzyć i przeanalizować. Co więcej, lista jest zwracana w kolejności chronologicznej, dzięki czemu możesz zobaczyć oznaczenia w kolejności ich wystąpienia w aplikacji internetowej.
Kod poniżej:
var items = window.performance.getEntriesByType('mark');
zwraca listę wszystkich znaków, które zostały użyte w naszej aplikacji internetowej, a kod:
var items = window.performance.getEntriesByType('measure');
zwraca listę wszystkich podjętych przez nas działań.
Możesz też pobrać listę wpisów, używając konkretnej nazwy, którą im nadasz. 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” w usłudze startTime
.
Czas żądania XHR (przykład)
Teraz, gdy mamy już wystarczającą wiedzę na temat 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 wysyłały wywołanie funkcji, które skonfiguruje znaczniki, a zarazem zmienimy nasze wywołania zwrotne sukcesu na wywołania funkcji, które skonfigurują inny znacznik, a następnie wygenerują miarę czasu trwania żądania.
Zazwyczaj nasza metoda XMLHttpRequest wyglądałaby 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 licznik globalny, który będzie śledził liczbę żądań i użyje go do przechowywania wartości 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 przez nas żądania XMLHttpRequest. Zakładamy, że żądania są wykonywane sekwencyjnie – kod dla żądań równoległych musiałby być nieco bardziej złożony, aby obsługiwać żądania zwracane w nieporządku. Pozostawiamy to jako ćwiczenie dla czytelnika.
Gdy aplikacja internetowa wykonała wiele żądań, możemy je wszystkie zapisać w 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 przydatnych narzędzi, które możesz stosować w dowolnym aspekcie aplikacji internetowej. Aby zlokalizować newralgiczne punkty w aplikacji, wystarczy rozmieścić w niej wywołania interfejsu API i przetworzyć wygenerowane dane dotyczące czasu, aby uzyskać jasny obraz tego, na co jest on tracony. Co jednak, jeśli Twoja przeglądarka nie obsługuje tego interfejsu API? Nie ma problemu. Tutaj znajdziesz świetne rozwiązanie polyfill, które dobrze emuluje interfejs API i działa z webpagetest.org. Na co więc czekasz? Wypróbuj interfejs User Timing API w swoich aplikacjach. Dzięki niemu dowiesz się, jak je przyspieszyć, a użytkownicy będą Ci wdzięczni za lepsze wrażenia.