Perché document.write è considerato una "cattiva pratica"?


363

So che document.writeè considerata una cattiva pratica; e spero di compilare un elenco di motivi per presentare a un fornitore di terze parti il ​​motivo per cui non dovrebbero utilizzare document.writenelle implementazioni del loro codice di analisi.

Di seguito, includi il motivo della richiesta di risarcimento document.writecome cattiva pratica.

Risposte:


243

Alcuni dei problemi più gravi:

  • document.write (d'ora in poi DW) non funziona in XHTML

  • DW non modifica direttamente il DOM, impedendo ulteriori manipolazioni (cercando di trovare prove di ciò, ma nella migliore delle ipotesi situazionali)

  • Il DW eseguito al termine del caricamento della pagina sovrascriverà la pagina o scriverà una nuova pagina o non funzionerà

  • DW viene eseguito dove rilevato: non può essere iniettato in un determinato punto del nodo

  • DW sta effettivamente scrivendo testo serializzato che non è il modo in cui il DOM funziona concettualmente ed è un modo semplice per creare bug (.innerHTML ha lo stesso problema)

Molto meglio usare i metodi di manipolazione DOM sicuri e compatibili con DOM


39
-1, modifica assolutamente il DOM. Tutto il resto va bene. Mentre comprendo l'impulso di dipendere dalla struttura e dai metodi che possono impedirti di nuocere, questo potrebbe essere il caso di buttare via il bambino con l'acqua del bagno.
CG

7
FireBug non è una rappresentazione fedele del DOM. È il tentativo di Mozilla di analizzare HTML in un DOM. È possibile che HTML completamente rotto sia corretto nella vista DOM Firebug.
FlySwat,

8
Il DOM è la struttura di dati utilizzata per il rendering della pagina e come tale è l'alfa e l'omega di ciò che l'utente vede sulla pagina. Hai ragione che HTML! = DOM, ma è irrilevante la questione se il DOM sia o meno modificato da DW. Se DW non ha modificato il DOM, non vedrai lo schermo - è vero per tutti i browser e sarà sempre finché il DOM è quello che viene utilizzato per il rendering della pagina.
CG

8
"DW esegue dove incontrato" - non sempre uno svantaggio, anzi potrebbe essere considerato un vantaggio per alcune cose, ad esempio l'aggiunta di elementi di script (in realtà l'unica cosa per cui avrei usato DW, e anche allora ci penserei due volte) .
nnnnnn,

7
@RicardoRivaldo Sì, lo fanno, se document.writeviene chiamato dopo che il documento ha terminato il caricamento
Izkata,

124

In realtà non c'è nulla di sbagliato in document.writesé. Il problema è che è davvero facile abusarne. Davvero, anche.

In termini di fornitori che forniscono codice analitico (come Google Analytics), in realtà è il modo più semplice per loro di distribuire tali frammenti

  1. Mantiene gli script piccoli
  2. Non devono preoccuparsi di ignorare gli eventi di caricamento già stabiliti o di includere l'astrazione necessaria per aggiungere eventi di caricamento in modo sicuro
  3. È estremamente compatibile

Finché non provi a usarlo dopo che il documento è stato caricato ,document.writenon è intrinsecamente malvagio, secondo la mia modesta opinione.


3
document.write fa cose davvero orribili con i parser html, ed è "estremamente compatibile" solo in casi semplici.
olliej,

27
Come l'inserimento di un tag analitico? Questo è, dopo tutto, parte della domanda originale. E per estremamente compatibile, intendo solo per il supporto del browser non elaborato per il metodo document.write.
Peter Bailey,

Tutto ciò che funziona con le ultime versioni di Chrome / IE / Safari / Opera / FireFox è considerato compatibile.
Pacerier,

2
Override degli eventi onload? E a cosa serve addEventListener?
m93a,

Chrome non eseguirà document.writeinvocazioni che inseriscono uno script quando vengono soddisfatte determinate condizioni.
Flimm,

44

Un altro uso legittimo document.writederiva dall'esempio 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>

Ho anche visto la stessa tecnica per utilizzare il polyfill di analisi / stringa JSON json2.js ( necessario per IE7 e versioni successive ).

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

11
Non un cattivo uso qui, ma ancora "migliore" per usare le funzioni di manipolazione del DOM - anche Google lo fa per Google Analytics. Lo snippet è qui .
BMiner

8
@BMiner se si inserisce un scriptelemento tramite manipolazione DOM, viene caricato in modo sincrono? A meno che non lo sia, non è un sostituto.
John Dvorak,

2
@JanDvorak - Un buon punto; quando si usano manipolazioni DOM, i browser generalmente caricano lo script in modo asincrono. È possibile utilizzare l' onloadevento DOM per determinare quando lo script caricato in modo asincrono è disponibile per l'uso.
BMiner

1
@JanDvorak Viene caricato in modo sincrono se non è esterno (non ha src) . Altrimenti verrà eseguito "il più presto possibile", in modo asincrono.
Oriol

1
Questo può ancora interrompersi, poiché Chrome rifiuta deliberatamente di eseguire document.writechiamate che inseriscono <script>tag se l'utente si trova su una connessione 2G. Vedi developers.google.com/web/updates/2016/08/…
Flimm,

42

Può bloccare la tua pagina

document.writeFunziona solo durante il caricamento della pagina; Se lo chiami dopo aver completato il caricamento della pagina, sovrascriverà l'intera pagina.

Questo significa effettivamente che devi chiamarlo da un blocco di script in linea - E ciò impedirà al browser di elaborare parti della pagina che seguono. Gli script e le immagini non verranno scaricati fino al completamento del blocco di scrittura.


32

Pro:

  • È il modo più semplice per incorporare contenuti incorporati da uno script esterno (al tuo host / dominio).
  • È possibile sovrascrivere l'intero contenuto in un frame / iframe. Usavo molto questa tecnica per i pezzi di menu / navigazione prima che fossero più ampiamente disponibili le più moderne tecniche Ajax (1998-2002).

con:

  • Serializza il motore di rendering in pausa fino a quando detto script esterno non viene caricato, il che potrebbe richiedere molto più tempo di uno script interno.
  • Di solito è usato in modo tale che lo script sia inserito nel contenuto, che è considerato in cattiva forma.

3
Ci sono più svantaggi di quello. Ad esempio, Google Chrome si rifiuterà di eseguire document.writeciò che crea <script>tag in determinate circostanze. developers.google.com/web/updates/2016/08/…
Flimm,

@Flimm vale la pena notare, il tuo commento è oltre 8 anni dopo la mia risposta e quasi 3 anni dopo. Sì, ci sono altri svantaggi ... e sarei sorpreso se document.write stesso non scompare ... così come forse alcune altre interfacce altamente abusate.
Tracker1

10

Ecco il mio valore di due anni, in generale non dovresti usare document.writeper il sollevamento di carichi pesanti, ma c'è un caso in cui è sicuramente utile:

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

L'ho scoperto di recente provando a creare una galleria di cursori AJAX. Ho creato due div annidati e applicato width/ heighte overflow: hiddenall'esterno <div>con JS. Questo in modo che, nel caso in cui il browser avesse JS disabilitato, il div galleggiava per ospitare le immagini nella galleria - un bel degrado grazioso.

La cosa è, come con l'articolo sopra, questo dirottamento JS del CSS non è entrato in azione fino a quando la pagina non è stata caricata, causando un lampo momentaneo mentre il div veniva caricato. Quindi avevo bisogno di scrivere una regola CSS, o includere un foglio, come pagina caricata.

Ovviamente, questo non funzionerà in XHTML, ma poiché XHTML sembra essere una specie di anatra morta (e viene visualizzato come tag soup in IE), varrebbe la pena rivalutare la tua scelta di DOCTYPE ...


7

Sovrascrive il contenuto della pagina che è il motivo più ovvio ma non lo definirei "cattivo".

Non serve molto a meno che non si stia creando un intero documento utilizzando JavaScript, nel qual caso è possibile iniziare con document.write.

Anche così, non stai davvero sfruttando il DOM quando usi document.write - stai semplicemente scaricando una goccia di testo nel documento, quindi direi che è una cattiva forma.


2
Un chiarimento: document.write inserisce i contenuti nella pagina, non li sovrascrive.
Peter Dolberg,

5
@Peter, sovrascrive il contenuto se lo chiami dopo il caricamento del documento. Immagino sia questo il significato di aleemb.
Matthew Crumley,

2
Stai suggerendo che si dovrebbe invece costruire manualmente i singoli nodi DOM nel codice piuttosto che fare qualcosa del genere div.innerHTML = "<label for='MySelect'>Choose One</label><select id='MySelect'><option value='foo' selected=''>foo</option><option value='bar'>bar</option></select>";? Sembra che produrrebbe un sacco di codice non necessario e meno leggibile. È anche l'esatto contrario dell'approccio che John Resig e altri sviluppatori JS sostengono.
Lèse majesté,

7

Rompe le pagine usando il rendering XML (come le pagine XHTML).

Migliore : alcuni browser tornano al rendering HTML e tutto funziona bene.

Probabile : alcuni browser disabilitano la funzione document.write () in modalità rendering XML.

Peggio ancora : alcuni browser generano un errore XML ogni volta che si utilizza la funzione document.write ().


6

In cima alla mia testa:

  1. document.writedeve essere utilizzato nel caricamento della pagina o nel corpo. Quindi, se si desidera utilizzare lo script in qualsiasi altro momento per aggiornare il documento del contenuto della pagina, scrivere è praticamente inutile.

  2. Tecnicamente document.writeaggiornerà solo le pagine HTML non XHTML / XML. IE sembra perdonare abbastanza questo fatto, ma altri browser non lo saranno.

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


9
IE sta perdonando perché non supporta XHTML. Se / quando lo fanno, document.write probabilmente smetterà di funzionare (solo in XHTML ovviamente).
Matthew Crumley,

2
XHTML è irrilevante sul web. Anche le pagine con un rigoroso doctype XHTML non sono in realtà trattate come XML al riguardo, gli sviluppatori di browser non si fidano così tanto degli autori delle pagine .
RobG,

4

Chrome potrebbe bloccare l' document.writeinserimento di uno script in alcuni casi. Quando ciò accade, verrà visualizzato questo avviso nella console:

Uno script con blocco incrociato, origine incrociata, ..., viene invocato tramite document.write. Questo potrebbe essere bloccato dal browser se il dispositivo ha una scarsa connettività di rete.

Riferimenti:


3

Violazione del browser

.writeè considerata una violazione del browser in quanto impedisce al parser di eseguire il rendering della pagina. Il parser riceve il messaggio che il documento è in fase di modifica; quindi, viene bloccato fino a quando JS non ha completato il suo processo. Solo in questo momento il parser riprenderà.

Prestazione

La principale conseguenza dell'utilizzo di tale metodo è la riduzione delle prestazioni. Il browser impiegherà più tempo a caricare il contenuto della pagina. La reazione avversa sul tempo di caricamento dipende da ciò che viene scritto nel documento. Non vedrai molta differenza se stai aggiungendo un <p>tag al DOM invece di passare un array di 50-alcuni riferimenti alle librerie JavaScript (qualcosa che ho visto nel codice di lavoro e ha provocato un ritardo di 11 secondi - di ovviamente, questo dipende anche dal tuo hardware).

Tutto sommato, è meglio evitare questo metodo se puoi aiutarlo.

Per ulteriori informazioni, consultare Intervening contro document.write ()


3

Sulla base dell'analisi effettuata da Lighthouse Audit di Google-Chrome Dev Tools ,

Per gli utenti con connessioni lente, gli script esterni iniettati dinamicamente tramite document.write()possono ritardare il caricamento della pagina di decine di secondi.

inserisci qui la descrizione dell'immagine


2
  • Un semplice motivo per cui document.writeè una cattiva pratica è che non è possibile elaborare uno scenario in cui non è possibile trovare un'alternativa migliore.
  • Un altro motivo è che hai a che fare con stringhe invece che con oggetti (è molto primitivo).
  • Si aggiunge solo ai documenti.
  • Non ha nulla della bellezza del modello MVC (Model-View-Controller) ad esempio .
  • È molto più potente presentare contenuti dinamici con ajax + jQuery o angularJS .

Per quanto riguarda il tuo primo proiettile, come risolverai ciò che @sunwukung descrive nella sua risposta sopra? Sono d'accordo che potresti risolverlo con manipolazioni DOM, ma man mano che le manipolazioni DOM vanno, è difficile evitare FUOC a volte senza document.write.
bert bruynooghe,

FUOC è più un problema?
Anders Lindén,

1

Si può pensare a document.write () (e .innerHTML) come a valutare una stringa di codice sorgente. Questo può essere molto utile per molte applicazioni. Ad esempio, se si ottiene il codice HTML come stringa da qualche sorgente, è utile semplicemente "valutarlo".

Nel contesto di Lisp, la manipolazione del DOM sarebbe come manipolare una struttura di elenco, ad esempio creare l'elenco (arancione) facendo:

(cons 'orange '())

E document.write () sarebbe come valutare una stringa, ad esempio creare un elenco valutando una stringa di codice sorgente come questa:

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

Lisp ha anche l'utilissima capacità di creare codice usando la manipolazione dell'elenco (come usare lo "stile DOM" per creare un albero di analisi JS). Ciò significa che è possibile creare una struttura di elenco utilizzando lo "stile DOM", anziché lo "stile stringa", quindi eseguire quel codice, ad esempio in questo modo:

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

Se si implementano strumenti di codifica, come semplici editor live, è molto utile poter valutare rapidamente una stringa, ad esempio utilizzando document.write () o .innerHTML. Lisp è l'ideale in questo senso, ma puoi fare cose molto interessanti anche in JS, e molte persone lo fanno, come http://jsbin.com/


1

Gli svantaggi di document.write dipendono principalmente da questi 3 fattori:

a) Implementazione

Document.write () viene utilizzato principalmente per scrivere contenuto sullo schermo non appena è necessario quel contenuto. Ciò significa che accade ovunque, in un file JavaScript o all'interno di un tag script all'interno di un file HTML. Con il tag di script posizionato ovunque all'interno di tale file HTML, è una cattiva idea avere istruzioni document.write () all'interno di blocchi di script che si intrecciano con HTML all'interno di una pagina web.

b) Rendering

Un codice ben progettato in generale prenderà qualsiasi contenuto generato dinamicamente, lo memorizzerà in memoria, continuerà a manipolarlo mentre passa attraverso il codice prima che venga finalmente sputato sullo schermo. Quindi, per ribadire l'ultimo punto della sezione precedente, il rendering del contenuto sul posto può essere reso più veloce di altri contenuti su cui si può fare affidamento, ma potrebbe non essere disponibile per l'altro codice che a sua volta richiede che il contenuto sia reso per l'elaborazione. Per risolvere questo dilemma dobbiamo liberarci di document.write () e implementarlo nel modo giusto.

c) Manipolazione impossibile

Una volta scritto, è finito e finito. Non possiamo tornare indietro per manipolarlo senza toccare il DOM.


1

Non credo che usare document.write sia una cattiva pratica. In parole semplici è come un'alta tensione per le persone inesperte. Se lo usi nel modo sbagliato, vieni cucinato. Ci sono molti sviluppatori che hanno usato questo e altri metodi pericolosi almeno una volta e non riescono mai a scavare nei loro fallimenti. Invece, quando qualcosa va storto, salvano e usano qualcosa di più sicuro. Quelli sono quelli che fanno tali dichiarazioni su quella che è considerata una "cattiva pratica".

È come formattare un disco rigido, quando è necessario eliminare solo pochi file e quindi dire "la formattazione del disco è una cattiva pratica".


-3

Penso che il problema più grande sia che tutti gli elementi scritti tramite document.write vengano aggiunti alla fine degli elementi della pagina. Questo è raramente l'effetto desiderato con i moderni layout di pagina e AJAX. (devi tenere presente che gli elementi nel DOM sono temporali e quando l'esecuzione dello script può influire sul suo comportamento).

È molto meglio impostare un elemento segnaposto sulla pagina, quindi manipolarlo innerHTML.


15
Questo non è vero. document.write non aggiunge il contenuto alla fine della pagina come se fosse un'appendice. Sono scritti sul posto.
Peter Bailey,

1
@Peter Bailey, so che questo è un vecchio thread, ma in realtà non dovrebbe essere sottoposto a downgrade. se si aggiunge o meno dipende dal fatto che document.write () funzioni in linea durante il caricamento della pagina. Se viene chiamato da una funzione dopo il caricamento della pagina, il primo document.write () sostituirà l'intero corpo e le successive chiamate verranno aggiunte ad esso.
Polpo,

3
@Octopus Sì, ma è circostanziale. Si aggiunge in quello scenario solo perché c'è un nuovo documento. Non è ancora corretto dire "document.write () accends". Sì, è una vecchia risposta e un vecchio downvote, ma rimango ancora lì.
Peter Bailey,

Va bene. Ho parlato in modo impreciso. L'avrei modificato molto tempo fa, ma sopra c'è una risposta molto migliore. Vorrei sottolineare che "scritto sul posto" è ugualmente impreciso.
BnWasteland,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.