Dlaczego document.write jest uważane za „złą praktykę”?


363

Wiem, że document.writejest uważane za złą praktykę; i mam nadzieję, że opracuję listę powodów, aby przesłać do zewnętrznego dostawcy, dlaczego nie powinni używać document.writew implementacjach swojego kodu analitycznego.

Podaj document.writeponiżej powód zgłoszenia złej praktyki.

Odpowiedzi:


243

Kilka poważniejszych problemów:

  • document.write (odtąd DW) nie działa w XHTML

  • DW nie modyfikuje bezpośrednio DOM, zapobiegając dalszej manipulacji (próbując znaleźć dowody na to, ale w najlepszym wypadku jest sytuacyjna)

  • DW wykonane po zakończeniu ładowania strony nadpisze stronę, napisze nową stronę lub nie będzie działać

  • DW wykonuje się tam, gdzie napotkano: nie może wstrzykiwać w danym punkcie węzła

  • DW skutecznie pisze serializowany tekst, który nie jest taki, jak DOM działa koncepcyjnie, i jest łatwym sposobem na tworzenie błędów (.innerHTML ma ten sam problem)

Zdecydowanie lepiej jest korzystać z bezpiecznych i przyjaznych DOM metod manipulacji DOM


39
-1, absolutnie modyfikuje DOM. Wszystko inne jest w porządku. Rozumiem potrzebę polegania na strukturze i metodach, które mogą uchronić cię przed krzywdą, ale może to być przypadek wyrzucenia dziecka z kąpielą.
cgp

7
FireBug nie jest prawdziwą reprezentacją DOM. Jest to próba parsowania Mozilli przez HTML na DOM. Możesz mieć całkowicie zepsuty wygląd HTML poprawnie w widoku DOM Firebug.
FlySwat,

8
DOM jest strukturą danych używaną do renderowania strony i jako taka jest alfą i omegą tego, co użytkownik widzi na stronie. Poprawny jest HTML! = DOM, ale nie ma znaczenia pytanie, czy DOM jest modyfikowany przez DW. Jeśli DW nie zmodyfikował DOM, ekran nie jest wyświetlany - dotyczy to wszystkich przeglądarek i zawsze będzie tak długo, jak DOM jest używany do renderowania strony.
cgp

8
„DW wykonuje się tam, gdzie napotkano” - nie zawsze jest to wada, w rzeczy samej można to uznać za zaletę w przypadku niektórych rzeczy, np. Dodawanie elementów skryptu (właściwie o jedynej rzeczy, do której używałbym DW, a nawet wtedy pomyślałem dwa razy) .
nnnnnn

7
@RicardoRivaldo Tak, robią to, jeśli document.writewywoływane jest po zakończeniu ładowania dokumentu
Izkata,

124

Właściwie nie ma w tym nic złego document.write. Problem polega na tym, że naprawdę łatwo go niewłaściwie użyć. Nawet rażąco.

Jeśli chodzi o dostawców dostarczających kod analityczny (np. Google Analytics), jest to w rzeczywistości najłatwiejszy sposób na rozpowszechnianie takich fragmentów

  1. Dzięki temu skrypty są małe
  2. Nie muszą się martwić o zastąpienie już ustanowionych zdarzeń onload lub dołączenie niezbędnej abstrakcji, aby bezpiecznie dodać zdarzenia onload
  3. Jest niezwykle kompatybilny

Tak długo, jak długo nie próbujesz go używać po załadowaniu dokumentu ,document.writenie jest on z natury zły, moim skromnym zdaniem.


3
document.write robi naprawdę okropne rzeczy z parserami HTML i jest „wyjątkowo kompatybilny” tylko w prostych przypadkach.
olliej

27
Jak wstawienie tagu analitycznego? To w końcu część pierwotnego pytania. I przez bardzo kompatybilny, mam na myśli jedynie surową obsługę przeglądarki dla metody document.write.
Peter Bailey

Wszystko, co działa z najnowszymi wersjami Chrome / IE / Safari / Opera / FireFox, jest uważane za kompatybilne.
Pacerier

2
Zastępujesz zdarzenia obciążenia? A po co addEventListener?
m93a

Chrome nie będzie działać document.write wywołań, które wstawią skrypt, jeśli zostaną spełnione określone warunki.
Flimm,

44

Kolejne uzasadnione użycie document.writepochodzi z przykładu HTML5 Boilerplate index.html .

<!-- Grab Google CDN's jQuery, with a protocol relative URL; fall back to local if offline -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/libs/jquery-1.6.3.min.js"><\/script>')</script>

Widziałem również tę samą technikę korzystania z wypełniania JSON json2.js funkcji parsowania / łączenia w polifill ( potrzebne dla IE7 i niższych ).

<script>window.JSON || document.write('<script src="json2.js"><\/script>')</script>

11
Nie jest to złe użycie tutaj, ale wciąż „lepsze” korzystanie z funkcji manipulacji DOM - nawet Google robi to dla Google Analytics. Snippet jest tutaj .
BMiner

8
@BMiner, jeśli wstawiasz scriptelement za pomocą manipulacji DOM, czy jest on ładowany synchronicznie? O ile nie jest, nie jest to zamiennik.
John Dvorak

2
@JanDvorak - Dobra uwaga; podczas korzystania z manipulacji DOM przeglądarki zazwyczaj ładują skrypt asynchronicznie. Za pomocą onloadzdarzenia DOM można określić, kiedy asynchronicznie załadowany skrypt jest dostępny do użycia.
BMiner

1
@JanDvorak Jest ładowany synchronicznie, jeśli nie jest zewnętrzny (nie ma src) . W przeciwnym razie zostanie on wykonany asynchronicznie „jak najszybciej”.
Oriol

1
To wciąż może się zepsuć, ponieważ Chrome celowo odmówi uruchomienia document.writepołączeń, które wstawiają <script>tagi, jeśli użytkownik ma połączenie 2G. Zobacz developers.google.com/web/updates/2016/08/…
Flimm

42

Może zablokować twoją stronę

document.writedziała tylko podczas ładowania strony; Jeśli zadzwonisz po załadowaniu strony, zastąpi ona całą stronę.

Oznacza to, że musisz wywołać go z wbudowanego bloku skryptu - a to uniemożliwi przeglądarce przetwarzanie części następnej strony. Skrypty i obrazy nie zostaną pobrane, dopóki blok zapisu nie zostanie ukończony.


31

Zawodowiec:

  • Jest to najprostszy sposób na osadzenie treści wbudowanej ze skryptu zewnętrznego (do hosta / domeny).
  • Możesz zastąpić całą treść ramką / ramką iframe. Często używałem tej techniki do tworzenia menu / elementów nawigacyjnych, zanim bardziej nowoczesne techniki Ajax były szeroko dostępne (1998-2002).

Kon:

  • Serializuje silnik renderujący, aby wstrzymać się do momentu załadowania wspomnianego skryptu zewnętrznego, co może potrwać znacznie dłużej niż skrypt wewnętrzny.
  • Zwykle jest używany w taki sposób, że skrypt jest umieszczony w treści, co jest uważane za niewłaściwe.

3
Istnieje więcej wad. Na przykład Google Chrome w pewnych okolicznościach odmówi uruchomienia, document.writektóry tworzy <script>tag. developers.google.com/web/updates/2016/08/…
Flimm

@Flimm warto zauważyć, twój komentarz jest ponad 8 lat po mojej odpowiedzi, a to prawie 3 lata później. Tak, istnieją inne wady ... i byłbym zaskoczony, gdyby samo document.write nie zniknęło ... jak również niektóre inne bardzo nadużywane interfejsy.
Tracker1

10

Oto moja wartość podwójna, na ogół nie powinieneś używać document.writedo podnoszenia ciężkich przedmiotów, ale jest jeden przypadek, w którym jest to zdecydowanie przydatne:

http://www.quirksmode.org/blog/archives/2005/06/three_javascrip_1.html

Odkryłem to niedawno próbując stworzyć galerię suwaków AJAX. Stworzyłem dwa zagnieżdżone div i zastosowałem width/ heighti overflow: hiddenna zewnętrz<div> pomocą JS. Było tak, że w przypadku, gdy przeglądarka wyłączyła JS, div będzie unosić się, aby pomieścić obrazy w galerii - trochę miłej wdzięcznej degradacji.

Chodzi o to, jak w powyższym artykule, to przejęcie CSS przez JS nie rozpoczęło się, dopóki strona się nie załadowała, powodując chwilowe flashowanie podczas ładowania div. Musiałem więc napisać regułę CSS lub dołączyć arkusz podczas ładowania strony.

Oczywiście nie będzie to działać w XHTML, ale ponieważ XHTML wydaje się być czymś w rodzaju martwej kaczki (i renderuje się jako zupa tag w IE), warto ponownie rozważyć wybór DOCTYPE ...


7

Zastępuje treść na stronie, co jest najbardziej oczywistym powodem, ale nie nazwałbym tego „złym”.

Po prostu nie ma większego zastosowania, chyba że tworzysz cały dokument za pomocą JavaScript, w takim przypadku możesz zacząć od document.write.

Mimo to, tak naprawdę nie używasz DOM, gdy używasz document.write - po prostu zrzucasz kroplę tekstu do dokumentu, więc powiedziałbym, że to zła forma.


2
Jedno wyjaśnienie: document.write wstawia zawartość na stronę, nie zastępuje ich.
Peter Dolberg

5
@Peter, nadpisuje zawartość, jeśli wywołasz ją po załadowaniu dokumentu. Zgaduję, że to właśnie oznacza aleemb.
Matthew Crumley

2
Czy sugerujesz, że zamiast tego należy ręcznie budować poszczególne węzły DOM w kodzie, a nie tylko robić coś takiego div.innerHTML = "<label for='MySelect'>Choose One</label><select id='MySelect'><option value='foo' selected=''>foo</option><option value='bar'>bar</option></select>";? Wydaje się, że spowodowałoby to powstanie wielu niepotrzebnych i mniej czytelnych kodów. Jest to również dokładne przeciwieństwo podejścia, które popiera John Resig i inni programiści JS.
Lèse majesté

7

Łamie strony przy użyciu renderowania XML (podobnie jak strony XHTML).

Najlepsze : niektóre przeglądarki przełączają się z powrotem na renderowanie HTML i wszystko działa dobrze.

Prawdopodobne : niektóre przeglądarki wyłączają funkcję document.write () w trybie renderowania XML.

Najgorsze : niektóre przeglądarki wywołują błąd XML przy każdym użyciu funkcji document.write ().


6

Z czubka mojej głowy:

  1. document.writemusi być używany do ładowania strony lub treści. Więc jeśli chcesz użyć skryptu w dowolnym momencie, aby zaktualizować zawartość strony document.write jest prawie bezużyteczne.

  2. Technicznie document.writezaktualizuje tylko strony HTML, a nie XHTML / XML. IE wydaje się dość wybaczać temu faktowi, ale inne przeglądarki tak nie będą.

http://www.w3.org/MarkUp/2004/xhtml-faq#docwrite


9
IE wybacza, ponieważ nie obsługuje XHTML. Jeśli / kiedy to zrobią, document.write prawdopodobnie przestanie działać (oczywiście tylko w XHTML).
Matthew Crumley,

2
XHTML nie ma znaczenia w sieci. Nawet strony o ścisłym typie XHTML nie są traktowane pod tym względem jako XML, twórcy przeglądarek nie ufają tak bardzo autorom stron .
RobG

4

document.writeW niektórych przypadkach Chrome może blokować wstawianie skryptu. Gdy tak się stanie, wyświetli to ostrzeżenie w konsoli:

Skrypt blokujący parser, pochodzący z różnych źródeł, ..., jest wywoływany przez document.write. Może to zostać zablokowane przez przeglądarkę, jeśli urządzenie ma słabą łączność sieciową.

Bibliografia:


3

Naruszenie przeglądarki

.writejest uważane za naruszenie przeglądarki, ponieważ powstrzymuje parser przed renderowaniem strony. Analizator składni otrzymuje komunikat, że dokument jest modyfikowany; dlatego zostaje zablokowany, dopóki JS nie zakończy procesu. Tylko w tym momencie parser zostanie wznowiony.

Wydajność

Największą konsekwencją zastosowania takiej metody jest obniżona wydajność. Wczytywanie zawartości strony potrwa dłużej. Niekorzystna reakcja na czas ładowania zależy od tego, co jest zapisywane w dokumencie. Nie zobaczysz dużej różnicy, jeśli dodasz <p>znacznik do DOM w przeciwieństwie do przekazywania tablicy 50-niektórych odniesień do bibliotek JavaScript (coś, co widziałem w działającym kodzie i spowodowało 11-sekundowe opóźnienie - oczywiście zależy to również od sprzętu).

Podsumowując, najlepiej jest unikać tej metody, jeśli możesz jej pomóc.

Aby uzyskać więcej informacji, zobacz interweniowanie przeciwko document.write ()


3

Na podstawie analizy przeprowadzonej przez Google-Chrome Dev Tools Audit Lighthouse Audit ,

W przypadku użytkowników korzystających z wolnych połączeń zewnętrzne skrypty dynamicznie wprowadzane za pośrednictwem document.write()mogą opóźnić ładowanie strony o kilkadziesiąt sekund.

wprowadź opis zdjęcia tutaj


2
  • Prosty powód dlaczego document.write złej praktyki jest to, że nie można wymyślić scenariusza, w którym nie można znaleźć lepszej alternatywy.
  • Innym powodem jest to, że masz do czynienia z łańcuchami zamiast z obiektami (jest to bardzo prymitywne).
  • Dotyczy tylko dokumentów.
  • Nie ma w tym nic pięknego, na przykład wzór MVC (Model-View-Controller) .
  • O wiele bardziej wydajne jest przedstawianie zawartości dynamicznej za pomocą ajax + jQuery lub angularJS .

Co do pierwszej kuli, jak rozwiążesz to, co @sunwukung opisuje w swojej odpowiedzi powyżej? Zgadzam się, że można to rozwiązać za pomocą manipulacji DOM, ale wraz z manipulacjami DOM trudno jest uniknąć FUOC czasami document.write.
bert bruynooghe

Czy FUOC jest już problemem?
Anders Lindén,

1

Można myśleć o document.write () (i .innerHTML) jako o ocenie ciągu kodu źródłowego. Może to być bardzo przydatne w wielu aplikacjach. Na przykład, jeśli otrzymujesz kod HTML jako ciąg znaków z jakiegoś źródła, dobrze jest po prostu go „ocenić”.

W kontekście Lisp manipulowanie DOM byłoby jak manipulowanie strukturą listy, np. Tworzenie listy (pomarańczowy) poprzez:

(cons 'orange '())

A document.write () byłoby jak ocena łańcucha, np. Utwórz listę, oceniając łańcuch kodu źródłowego w następujący sposób:

(eval-string "(cons 'orange '())")

Lisp ma również bardzo przydatną zdolność do tworzenia kodu przy użyciu manipulacji listami (np. Przy użyciu „stylu DOM” do utworzenia drzewa parsowania JS). Oznacza to, że możesz zbudować strukturę listy za pomocą „stylu DOM”, a nie „stylu ciągu”, a następnie uruchomić ten kod, np. W następujący sposób:

(eval '(cons 'orange '()))

Jeśli zaimplementujesz narzędzia do kodowania, takie jak proste edytory na żywo, bardzo przydatna jest możliwość szybkiej oceny ciągu, na przykład za pomocą document.write () lub .innerHTML. Lisp jest w tym sensie idealny, ale możesz robić bardzo fajne rzeczy również w JS, a wiele osób to robi, np. Http://jsbin.com/


1

Wady document.write zależą głównie od 3 czynników:

a) Wdrożenie

Document.write () jest najczęściej używany do zapisywania zawartości na ekranie, gdy tylko ta zawartość jest potrzebna. Oznacza to, że dzieje się to w dowolnym miejscu, w pliku JavaScript lub w znaczniku skryptu w pliku HTML. Umieszczenie znacznika skryptu w dowolnym miejscu takiego pliku HTML jest złym pomysłem, aby mieć instrukcje document.write () w blokach skryptu, które są powiązane z HTML wewnątrz strony internetowej.

b) Rendering

Dobrze zaprojektowany kod ogólnie bierze każdą dynamicznie generowaną zawartość, przechowuje ją w pamięci, ciągle manipuluje nią, gdy przechodzi przez kod, zanim w końcu zostanie wyrzucony na ekran. Aby powtórzyć ostatni punkt w poprzedniej sekcji, renderowanie zawartości w miejscu może być renderowane szybciej niż w przypadku innych treści, na których można polegać, ale może nie być dostępne dla innego kodu, który z kolei wymaga renderowania treści do przetworzenia. Aby rozwiązać ten dylemat, musimy pozbyć się document.write () i zaimplementować go we właściwy sposób.

c) Niemożliwa manipulacja

Po napisaniu jest skończone. Nie możemy wrócić, aby nim manipulować bez dotykania DOM.


1

Nie sądzę, aby korzystanie z document.write w ogóle było złą praktyką. Krótko mówiąc, jest to wysokie napięcie dla niedoświadczonych ludzi. Jeśli użyjesz go w niewłaściwy sposób, zostaniesz ugotowany. Jest wielu programistów, którzy przynajmniej raz zastosowali tę i inne niebezpieczne metody i nigdy tak naprawdę nie zagłębili się w swoje niepowodzenia. Zamiast tego, gdy coś pójdzie nie tak, po prostu ratują i używają czegoś bezpieczniejszego. To oni wypowiadają się na temat tego, co uważa się za „złą praktykę”.

To jak formatowanie dysku twardego, kiedy trzeba usunąć tylko kilka plików, a następnie powiedzieć „formatowanie dysku to zła praktyka”.


-3

Myślę, że największym problemem jest to, że wszelkie elementy napisane przez document.write są dodawane na końcu elementów strony. Rzadko jest to pożądany efekt w przypadku nowoczesnych układów stron i AJAX. (należy pamiętać, że elementy w DOM są tymczasowe, a uruchomienie skryptu może wpłynąć na jego zachowanie).

O wiele lepiej jest ustawić element zastępczy na stronie, a następnie manipulować jego innerHTML.


15
To nie jest prawda. document.write nie dodaje zawartości na końcu strony tak, jakby była dopisem. Są napisane na miejscu.
Peter Bailey,

1
@Peter Bailey, wiem, że to stary wątek, ale tak naprawdę nie należy go lekceważyć. to, czy zostanie dołączone, zależy od tego, czy document.write () działa w linii podczas ładowania strony. Jeśli zostanie wywołana z funkcji po załadowaniu strony, pierwszy document.write () zastąpi całe ciało, a kolejne wywołania do niego dołączą.
Octopus,

3
@Octopus Tak, ale to poszlaki. Dołącza się w tym scenariuszu tylko dlatego, że jest nowy dokument. Nadal nie jest poprawne stwierdzenie „dołącza document.write ()”. Tak, to stara odpowiedź i stara opinia negatywna, ale nadal jestem przy niej.
Peter Bailey,

W porządku. Mówiłem nieprecyzyjnie. Zrobiłbym to już dawno, ale powyżej jest o wiele lepsza odpowiedź. Chciałbym jednak zaznaczyć, że „napisane na miejscu” jest równie nieprecyzyjne.
BnWasteland
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.