Kod JavaScript często powoduje zmiany wizualne. Czasami jest to bezpośrednio przez manipulowanie stylem, a czasami przez obliczenia, które powodują zmiany wizualne, takie jak wyszukiwanie lub sortowanie danych. Złe ustawienie czasu lub długi czas działania kodu JavaScript to częste przyczyny problemów ze skutecznością. W miarę możliwości staraj się minimalizować wpływ tych zmian.
Kod JavaScript często powoduje zmiany wizualne. Czasami jest to bezpośrednio manipulowanie stylem, a czasami obliczenia, które powodują zmiany wizualne, takie jak wyszukiwanie lub sortowanie danych. Złe ustawienie lub długi czas wykonywania kodu JavaScript to częsta przyczyna problemów z wydajnością. W miarę możliwości staraj się minimalizować wpływ tych zmian.
Profilowanie wydajności kodu JavaScript może być sztuką, ponieważ napisany przez Ciebie kod JavaScript nie przypomina w ogóle kodu, który jest faktycznie wykonywany. Nowoczesne przeglądarki korzystają z kompilacji JIT oraz różnych optymalizacji i sztuczek, aby zapewnić możliwie najszybsze wykonanie. W związku z tym znacznie zmienia się dynamika kodu.
Mimo to możesz wykonać kilka czynności, które z pewnością pomogą Twoim aplikacjom w skutecznym wykonywaniu kodu JavaScript.
Podsumowanie
- Unikaj wywoływania metody setTimeout lub setInterval w celu aktualizacji wizualnych. Zamiast tego zawsze używaj metody requestAnimationFrame.
- Przenoś długo działający kod JavaScript z wątku głównego do skryptów Web Worker.
- Stosuj mikrozadania, aby wprowadzać zmiany w DOM na przestrzeni kilku klatek.
- Aby ocenić wpływ kodu JavaScript, użyj osi czasu i profilowania JavaScriptu w Narzędziach deweloperskich w Chrome.
Aby wprowadzić zmiany wizualne, użyj elementu requestAnimationFrame
.
Gdy na ekranie pojawiają się zmiany wizualne, chcesz, aby Twoja praca była wykonywana w odpowiednim czasie dla przeglądarki, czyli na samym początku kadru. Jedynym sposobem na zagwarantowanie, że kod JavaScript będzie uruchamiany na początku kadru, jest użycie requestAnimationFrame
.
/**
* If run as a requestAnimationFrame callback, this
* will be run at the start of the frame.
*/
function updateScreen(time) {
// Make visual updates here.
}
requestAnimationFrame(updateScreen);
Frameworki lub przykłady mogą używać funkcji setTimeout
lub setInterval
do wprowadzania zmian wizualnych, takich jak animacje. Problem polega na tym, że funkcja wywołania zwrotnego jest wykonywana w jakimś momencie w ramce, prawdopodobnie pod koniec, co często powoduje pominięcie klatki i więc zacięcia.
W zasadzie jQuery używała do tego celu funkcji setTimeout
.animate
W wersji 3 zmieniono go na requestAnimationFrame
.
Jeśli używasz starszej wersji jQuery, możesz zastosować do niej poprawkę, aby używać requestAnimationFrame
. Jest to zdecydowanie zalecane.
Zmniejsz złożoność lub użyj Web Workers
Kod JavaScript jest uruchamiany w głównym wątku przeglądarki, obok obliczeń stylów, układu i w wielu przypadkach renderowania. Jeśli kod JavaScript działa przez długi czas, będzie blokować te inne zadania, co może spowodować pominięcie klatek.
Należy określić, kiedy i jak długo ma działać JavaScript. Jeśli np. używasz animacji, takiej jak przewijanie, czas wykonywania kodu JavaScript powinien wynosić w najlepszym przypadku 3–4 ms. Jeśli będziesz dłużej czekać, możesz stracić zbyt dużo czasu. Jeśli masz czas na bezczynność, możesz sobie pozwolić na większy luz.
W wielu przypadkach możesz przenieść czystą pracę obliczeniową do Web Workers, jeśli na przykład nie wymaga ona dostępu do DOM. Manipulowanie danymi lub ich przeszukiwanie, takie jak sortowanie czy wyszukiwanie, często dobrze pasuje do tego modelu, podobnie jak wczytywanie i generowanie modelu.
var dataSortWorker = new Worker("sort-worker.js");
dataSortWorker.postMesssage(dataToSort);
// The main thread is now free to continue working on other things...
dataSortWorker.addEventListener('message', function(evt) {
var sortedData = evt.data;
// Update data on screen...
});
Nie wszystkie zadania mogą być wykonywane w ramach tego modelu: zadania Web Worker nie mają dostępu do DOM. Jeśli Twoja praca musi być wykonywana w wątku głównym, rozważ użycie podejścia zbiorczego, w którym większe zadanie dzielisz na mikrozadania, z których każde zajmuje nie więcej niż kilka milisekund, a następnie uruchamiasz je w ramach obsługi requestAnimationFrame
w każdej klatce.
Takie podejście ma konsekwencje w zakresie UX i UI. Musisz zadbać o to, aby użytkownik wiedział, że zadanie jest przetwarzane, np. za pomocą wskaźnika postępu lub aktywności. W każdym razie takie podejście pozwoli zachować wolny wątek główny aplikacji, dzięki czemu będzie ona lepiej reagować na interakcje z użytkownikiem.
Poznaj „podatek od ramki” w JavaScript
Podczas oceny frameworka, biblioteki lub własnego kodu należy sprawdzić, ile kosztuje wykonanie kodu JavaScript na podstawie poszczególnych klatek. Jest to szczególnie ważne w przypadku animacji, w których przypadku liczy się wydajność, np. podczas przechodzenia między klatkami czy przewijania.
Panel Wydajność w Narzędziach deweloperskich w Chrome to najlepszy sposób na pomiar kosztu kodu JavaScript. Zwykle otrzymujesz rekordy niskiego poziomu takie jak ten:
W sekcji Główna znajduje się wykres płomienisty wywołań kodu JavaScript, dzięki któremu możesz dokładnie analizować, które funkcje zostały wywołane i jak długo trwało ich wykonanie.
Dzięki tym informacjom możesz ocenić wpływ kodu JavaScript na wydajność aplikacji i zacząć znajdować oraz rozwiązywać problemy, które powodują zbyt długi czas wykonywania funkcji. Jak już wspomnieliśmy, należy usunąć długo działający kod JavaScript lub, jeśli to niemożliwe, przenieść go do Web Workera, aby zwolnić wątek główny i umożliwić kontynuowanie wykonywania innych zadań.
Aby dowiedzieć się, jak korzystać z panelu Wydajność, przeczytaj artykuł Pierwsze kroki w analizowaniu wydajności w czasie wykonywania kodu.
Unikaj mikrooptymalizacji kodu JavaScriptu
Może być ciekawe, że przeglądarka może wykonać jedną wersję czegoś 100 razy szybciej niż inną, np. że wczytywanie offsetTop
elementu jest szybsze niż wykonywanie getBoundingClientRect()
, ale prawie zawsze będziesz wywoływać takie funkcje tylko kilka razy na kadr, więc skupianie się na tym aspekcie wydajności kodu JavaScript jest zwykle stratą czasu. Zwykle oszczędzasz tylko ułamki milisekund.
Jeśli tworzysz grę lub aplikację wymagającą dużych zasobów obliczeniowych, prawdopodobnie nie dotyczy Cię ta wskazówka, ponieważ zwykle w ramach jednego klatki obrazuujesz wiele obliczeń, a w tym przypadku wszystko się przydaje.
Krótko mówiąc, należy bardzo uważać na mikrooptymalizacje, ponieważ zwykle nie pasują one do rodzaju aplikacji, którą tworzysz.