Dodawanie elementów interaktywnych za pomocą JavaScriptu

Umożliwia on modyfikowanie niemal każdego aspektu strony: treści, stylu i reakcji na interakcje użytkowników. Jednak JavaScript może też blokować konstrukcję DOM i opóźniać renderowanie strony. Aby uzyskać optymalną wydajność, zastosuj asynchroniczny JavaScript i usuń niepotrzebne elementy z krytycznej ścieżki renderowania.

Podsumowanie

  • JavaScript może wysyłać zapytania do obiektów DOM i CSSOM oraz modyfikować je.
  • Bloki wykonywania JavaScriptu w CSSOM.
  • JavaScript blokuje konstrukcję DOM, chyba że zostanie wyraźnie oznaczony jako asynchroniczny.

JavaScript to dynamiczny język, który działa w przeglądarce i umożliwia zmianę niemal każdego aspektu działania strony: możemy modyfikować treść, dodając i usuwając elementy z drzewa DOM, możemy modyfikować właściwości CSSOM każdego elementu, możemy obsługiwać dane wejściowe użytkownika oraz wiele innych opcji. Aby to zilustrować, uzupełnimy poprzedni przykład „Hello World” prostym, wbudowanym skryptem:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link href="style.css" rel="stylesheet" />
    <title>Critical Path: Script</title>
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg" /></div>
    <script>
      var span = document.getElementsByTagName('span')[0];
      span.textContent = 'interactive'; // change DOM text content
      span.style.display = 'inline'; // change CSSOM property
      // create a new element, style it, and append it to the DOM
      var loadTime = document.createElement('div');
      loadTime.textContent = 'You loaded this page on: ' + new Date();
      loadTime.style.color = 'blue';
      document.body.appendChild(loadTime);
    </script>
  </body>
</html>

Wypróbuj

  • JavaScript umożliwia nam dotarcie do interfejsu DOM i wyciąganie odwołania do ukrytego węzła spanu. Węzeł może nie być widoczny w drzewie renderowania, ale nadal znajduje się w DOM. Następnie, mając odniesienie, możemy zmienić jego tekst (za pomocą tagu .textContent), a nawet zastąpić obliczoną właściwość stylu wyświetlania z „none” na „inline”. Teraz na naszej stronie wyświetli się komunikat „Cześć, uczniowie!”.

  • JavaScript umożliwia też tworzenie, stylizowanie, dołączanie i usuwanie nowych elementów w DOM. Technicznie rzecz biorąc, cała strona mogłaby być pojedynczym dużym plikiem JavaScript, który tworzy i stylizuje elementy jeden po drugim. Chociaż byłoby to możliwe, w praktyce korzystanie z HTML i CSS jest znacznie łatwiejsze. W drugiej części naszej funkcji JavaScript tworzymy nowy element div, ustawiamy jego treść tekstową, określamy jej styl i dołączasz do treści.

podgląd strony

W związku z tym zmodyfikowaliśmy zawartość oraz styl CSS istniejącego węzła DOM i dodaliśmy do dokumentu zupełnie nowy węzeł. Ta strona nie wygra żadnych nagród za projektowanie, ale pokazuje możliwości i elastyczność, jakie daje nam JavaScript.

Co prawda JavaScript daje nam wiele możliwości, ale nakłada wiele dodatkowych ograniczeń w zakresie sposobu i czasu renderowania strony.

Po pierwsze, zwróć uwagę na to, że w powyższym przykładzie nasz wbudowany skrypt znajduje się u dołu strony. Dlaczego? Możesz spróbować samodzielnie. Jeśli jednak przesuniesz skrypt na element span, zauważysz, że skrypt ulegnie awarii i zgłosi, że nie może znaleźć odwołania do żadnych elementów span w dokumencie – to znaczy, że getElementsByTagName(‘span') zwraca wartość null. To dowód na ważną właściwość: nasz skrypt jest wykonywany dokładnie w tym miejscu, w którym został wstawiony w dokumencie. Gdy parser HTML napotka tag skryptu, wstrzymuje proces tworzenia modelu DOM i przekazuje kontrolę silnikowi JavaScript. Po zakończeniu działania mechanizmu JavaScript przeglądarka wraca do miejsca, w którym została wstrzymana, i wznawia konstrukcję DOM.

Inaczej mówiąc, nasz blok skryptu nie może odnaleźć żadnych elementów w dalszej części strony, ponieważ nie zostały one jeszcze przetworzone. Albo inaczej: wykonanie wbudowanego skryptu blokuje konstrukcję DOM, co również opóźnia wstępne renderowanie.

Kolejną subtelną właściwością przedstawiającą skrypty na stronie jest to, że mogą one odczytywać i modyfikować nie tylko model DOM, ale także właściwości CSSOM. Właśnie to robimy w naszym przykładzie, zmieniając właściwość wyświetlania elementu span z „brak” na „inline”. Jaki jest efekt końcowy? Mamy teraz warunek wyścigu.

Co się stanie, jeśli przeglądarka nie zakończy pobierania i tworzenia CSSOM, a potem uruchomimy nasz skrypt? Odpowiedź jest prosta i niezbyt dobra pod względem wydajności: przeglądarka opóźnia wykonanie skryptu i konstrukcję DOM, dopóki nie skończy pobierać i tworzyć CSSOM.

Krótko mówiąc, JavaScript wprowadza wiele nowych zależności między wykonywaniem DOM, CSSOM i JavaScriptu. Może to spowodować znaczne opóźnienia w przetwarzaniu i renderowaniu strony na ekranie:

  • Lokalizacja skryptu w dokumencie jest istotna.
  • Gdy przeglądarka napotyka tag skryptu, konstrukcja DOM jest wstrzymywana do czasu zakończenia działania skryptu.
  • JavaScript może wysyłać zapytania do obiektów DOM i CSSOM oraz modyfikować je.
  • Wykonanie JavaScript jest wstrzymywane do czasu, aż CSSOM będzie gotowy.

Termin „optymalizacja krytycznej ścieżki renderowania” odnosi się w dużej mierze do zrozumienia i zoptymalizowania wykresu zależności między HTML, CSS i JavaScript.

Blokowanie parsera a asynchroniczny JavaScript

Domyślne działanie JavaScriptu to „blokowanie parsera” – gdy przeglądarka napotka skrypt w dokumencie, przed kontynuacją konstrukcji DOM musi wstrzymać konstrukcję DOM, przekazać kontrolę do środowiska wykonawczego JavaScript i pozwolić na wykonanie skryptu. Zauważyliśmy, że robimy to w praktyce przy użyciu wbudowanego skryptu. W rzeczywistości skrypty wbudowane zawsze blokują działanie parsera, chyba że napiszesz dodatkowy kod, który odroczy ich wykonanie.

Co ze skryptami dodawanymi przez tag skryptu? Przeanalizujmy poprzedni przykład i wyodrębmy kod do osobnego pliku:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link href="style.css" rel="stylesheet" />
    <title>Critical Path: Script External</title>
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg" /></div>
    <script src="app.js"></script>
  </body>
</html>

app.js

var span = document.getElementsByTagName('span')[0];
span.textContent = 'interactive'; // change DOM text content
span.style.display = 'inline'; // change CSSOM property
// create a new element, style it, and append it to the DOM
var loadTime = document.createElement('div');
loadTime.textContent = 'You loaded this page on: ' + new Date();
loadTime.style.color = 'blue';
document.body.appendChild(loadTime);

Wypróbuj

Zarówno tag <script>, jak i wbudowany fragment kodu JavaScriptu powinny działać w ten sam sposób. W obu przypadkach przeglądarka wstrzymuje i uruchamia skrypt, zanim będzie w stanie przetworzyć pozostałą część dokumentu. W przypadku zewnętrznego pliku JavaScript przeglądarka musi jednak wstrzymać się do czasu pobrania skryptu z dysku, pamięci podręcznej lub serwera zdalnego, co może wydłużyć krytyczne opóźnienie renderowania o dziesiątki lub tysiące milisekund.

Domyślnie cały kod JavaScript blokuje parser. Przeglądarka nie wie, co skrypt planuje zrobić na stronie, więc przyjmuje najgorszy scenariusz i blokuje parser. Sygnał dla przeglądarki, że skrypt nie musi zostać wykonany w miejscu, w którym się on znajduje, umożliwia przeglądarce kontynuowanie tworzenia modelu DOM i pozwala na wykonanie skryptu, gdy będzie gotowy, na przykład po pobraniu pliku z pamięci podręcznej lub serwera zdalnego.

Aby to osiągnąć, oznaczamy skrypt jako async:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link href="style.css" rel="stylesheet" />
    <title>Critical Path: Script Async</title>
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg" /></div>
    <script src="app.js" async></script>
  </body>
</html>

Wypróbuj

Dodanie asynchronicznego słowa kluczowego do tagu skryptu informuje przeglądarkę, aby nie blokowała konstrukcji DOM podczas oczekiwania na udostępnienie skryptu, co może znacznie zwiększyć wydajność.

Prześlij opinię