Interakcja z metodą document.write()

Czy zdarzyło Ci się ostatnio w Konsoli programisty w Chrome zobaczyć takie ostrzeżenie i zastanawiasz się, co ono oznacza?

(index):34 A Parser-blocking, cross-origin script,
https://paul.kinlan.me/ad-inject.js, is invoked via document.write().
This may be blocked by the browser if the device has poor network connectivity.

Kompozycja to jedna z największych możliwości internetu, która pozwala nam na łatwą integrację z usługami innych firm w celu tworzenia świetnych nowych produktów. Jedną z wad tego rozwiązania jest to, że obejmuje wspólną odpowiedzialność za wrażenia użytkownika. Jeśli integracja nie będzie optymalna, wpłynie to negatywnie na wrażenia użytkowników.

Jedną ze znanych przyczyn niskiej wydajności jest stosowanie elementu document.write() na stronach, a zwłaszcza na stronach, które powodują wstrzykiwanie skryptów. Chociaż nie jest to oczywiste, może to powodować realne problemy u użytkowników.

document.write('<script src="https://example.com/ad-inject.js"></script>');

Zanim przeglądarka będzie mogła wyrenderować stronę, musi utworzyć drzewo DOM przez analizę znaczników HTML. Gdy parser napotka skrypt, musi go zatrzymać i wykonać, zanim będzie mógł kontynuować analizę kodu HTML. Jeśli skrypt dynamicznie wstrzykuje inny skrypt, parser będzie musiał jeszcze dłużej czekać na pobranie zasobu, co może spowodować jedną lub kilka transferów danych w obie strony i opóźnienie pierwszego wyrenderowania strony.

W przypadku użytkowników, którzy korzystają z wolnych połączeń, np. 2G, skrypty zewnętrzne wstawiane dynamicznie przez document.write() mogą opóźnić wyświetlanie zawartości strony głównej o kilka sekund albo spowodować, że strony się nie wczytają lub będą się one wczytywać tak długo, że użytkownik się zakończy. Na podstawie instrumentacji dostępnych w Chrome dowiedzieliśmy się, że strony zawierające skrypty innych firm wstawiane przez document.write() zwykle wczytują się dwukrotnie wolniej niż inne strony w sieci 2G.

Zebraliśmy dane z 28-dniowego okresu próbnego obejmującego 1% użytkowników wersji stabilnej Chrome. Dotyczy to tylko użytkowników korzystających z połączeń 2G. Zauważyliśmy, że 7,6% wszystkich operacji wczytywania stron w sieci 2G obejmowało co najmniej 1 skrypt blokowania parsera w różnych witrynach, który został wstawiony za pomocą document.write() w dokumencie najwyższego poziomu. W wyniku blokowania wczytywania skryptów zaobserwowaliśmy następujące ulepszenia:

  • O 10% więcej ładowanych stron, które osiągają pierwsze wyrenderowanie treści (wizualne potwierdzenie, że strona prawidłowo się wczytuje), o 25% więcej stron wczytuje się w stanie w pełni przeanalizowanej, a o 10% mniej przypadków ponownego wczytywania, co zmniejsza frustrację użytkowników.
  • skrócenie średniego czasu (o ponad 1 sekundę) do pierwszego wyrenderowania treści o 21%
  • Skrócenie średniego czasu potrzebnego na analizę strony o 38% oznacza skrócenie czasu potrzebnego na analizę o prawie 6 sekund, co znacznie skróciło czas potrzebny na wyświetlenie użytkownikowi tego, co istotne.

Mając to na uwadze, Chrome, począwszy od wersji 55, interwuje się w imieniu wszystkich użytkowników, gdy wykryje ten znany zły wzorzec, zmieniając sposób obsługi document.write() w Chrome (zobacz Stan Chrome). W szczególności Chrome nie uruchomi elementów <script> wstrzykiwanych przez document.write(), gdy zostaną spełnione wszystkie te warunki:

  1. Użytkownik ma wolne połączenie, zwłaszcza gdy korzysta z sieci 2G. (W przyszłości zmiana może dotyczyć również innych użytkowników korzystających z wolnego połączenia, np. 3G lub Wi-Fi).
  2. document.write() jest w dokumencie najwyższego poziomu. Ta interwencja nie dotyczy skryptów document.letter w elementach iframe, ponieważ nie blokują one renderowania strony głównej.
  3. Skrypt w pliku document.write() blokuje parser. Skrypty z atrybutami „async” lub „defer” nadal będą wykonywane.
  4. Skrypt nie jest hostowany w tej samej witrynie. Inaczej mówiąc, Chrome nie przeprowadzi interwencji w sprawie skryptów z pasującym eTLD+1 (np. skrypt hostowany na js.example.org wstawiony w witrynie www.example.org).
  5. Skryptu nie ma jeszcze w pamięci podręcznej HTTP przeglądarki. Skrypty w pamięci podręcznej nie powodują opóźnienia sieciowego i nadal są wykonywane.
  6. Żądanie nie dotyczy ponownego wczytania strony. Jeśli użytkownik załaduje stronę ponownie i wykona stronę w zwykły sposób, Chrome nie podejmie żadnych działań.

Fragmenty kodu innych firm czasami wczytują skrypty za pomocą polecenia document.write(). Na szczęście większość firm zewnętrznych udostępnia alternatywne sposoby ładowania asynchronicznego, które umożliwiają wczytywanie skryptów innych firm bez blokowania wyświetlania reszty treści na stronie.

Jak rozwiązać ten problem?

Ta prosta odpowiedź brzmi: nie wstrzykuj skryptów za pomocą polecenia document.write(). Utrzymujemy zestaw znanych usług do obsługi asynchronicznego ładowania, które zachęcamy do regularnego sprawdzania.

Jeśli Twojego dostawcy nie ma na liście, a obsługuje on asynchroniczne ładowanie skryptów, daj nam znać, a będziemy mogli zaktualizować stronę, aby pomóc wszystkim użytkownikom.

Jeśli Twój dostawca nie obsługuje asynchronicznego wczytywania skryptów na Twojej stronie, skontaktuj się z nim i poinformuj nas, jaki to będzie miało wpływ na tę funkcję.

Jeśli dostawca udostępnia fragment kodu, który zawiera interfejs document.write(), możesz dodać atrybut async do elementu skryptu lub dodać elementy skryptu za pomocą interfejsu DOM API typu document.appendChild() lub parentNode.insertBefore().

Jak sprawdzić, czy zmiany wpływają na Twoją witrynę

Jest wiele kryteriów, które określają, czy dane ograniczenie jest egzekwowane, więc skąd możesz wiedzieć, czy Cię ono dotyczy?

Wykrywanie, kiedy użytkownik korzysta z sieci 2G

Aby poznać potencjalny wpływ tej zmiany, musisz się najpierw dowiedzieć, ilu Twoich użytkowników będzie korzystać z sieci 2G. Aby określić bieżący typ i szybkość sieci użytkownika, możesz użyć interfejsu Network Information API, dostępnego w Chrome, a następnie wysłać ostrzeżenie do systemów analitycznych lub Real User Metrics (RUM).

if(navigator.connection &&
    navigator.connection.type === 'cellular' &&
    navigator.connection.downlinkMax <= 0.115) {
    // Notify your service to indicate that you might be affected by this restriction.
}

Wykrywanie ostrzeżeń w Narzędziach deweloperskich w Chrome

Od wersji Chrome 53 Narzędzia deweloperskie generują ostrzeżenia dotyczące problematycznych instrukcji document.write(). W szczególności, jeśli żądanie document.write() spełnia kryteria z zakresu 2–5 (Chrome zignoruje kryteria połączenia podczas wysyłania tego ostrzeżenia), ostrzeżenie będzie wyglądać mniej więcej tak:

Ostrzeżenie przed zapisem dokumentu.

Ostrzeżenia w Narzędziach deweloperskich w Chrome są dobrze widoczne, ale jak wykrywają je na dużą skalę? Możesz sprawdzić, które nagłówki HTTP są wysyłane na Twój serwer po wystąpieniu interwencji.

Sprawdź nagłówki HTTP zasobu skryptu

Po zablokowaniu skryptu wstawionego przez document.write Chrome wyśle do żądanego zasobu ten nagłówek:

Intervention: <https://shorturl/relevant/spec>;

Gdy zostanie znaleziony skrypt wstawiony przez document.write i może być zablokowany w różnych okolicznościach, Chrome może wysłać:

Intervention: <https://shorturl/relevant/spec>; level="warning"

Nagłówek interwencji zostanie wysłany w ramach żądania GET skryptu (asynchronicznie w przypadku rzeczywistej interwencji).

Co niesie przyszłość?

Początkowy plan zakłada wykonanie tej interwencji, gdy wykryjemy spełnione kryteria. Zaczęliśmy od wyświetlania ostrzeżenia w Konsoli programisty w Chrome 53. (Wersja beta miała miejsce w lipcu 2016 r. Spodziewamy się, że wersja stabilna będzie dostępna dla wszystkich we wrześniu 2016 r.).

Podejmiemy interwencję w celu blokowania wstrzykiwanych skryptów dla użytkowników sieci 2G wstępnie od Chrome 54, który według szacunków powinien pojawić się jako stabilna wersja dla wszystkich użytkowników w połowie października 2016 r. Więcej informacji znajdziesz w artykule o stanie Chrome.

Z czasem staramy się także podjąć działania, aby rozwiązać problemy użytkowników z wolnym połączeniem (np.3G lub Wi-Fi). Postępuj zgodnie z tym wpisem o stanie Chrome.

Chcesz dowiedzieć się więcej?

Więcej informacji znajdziesz w tych dodatkowych materiałach: