¿Por qué se considera document.write una "mala práctica"?

363

Sé que document.writese considera una mala práctica; y espero compilar una lista de razones para enviar a un proveedor de terceros por qué no deberían usar document.writeen implementaciones de su código de análisis.

Incluya a continuación su razón para reclamar document.writecomo mala práctica.

FlySwat
fuente

Respuestas:

243

Algunos de los problemas más serios:

  • document.write (en adelante DW) no funciona en XHTML

  • DW no modifica directamente el DOM, evitando una mayor manipulación (tratando de encontrar evidencia de esto, pero en el mejor de los casos).

  • DW ejecutado después de que la página haya terminado de cargarse sobrescribirá la página, o escribirá una nueva página, o no funcionará

  • DW se ejecuta donde se encuentra: no puede inyectar en un punto de nodo dado

  • DW está escribiendo efectivamente texto serializado que no es la forma en que el DOM funciona conceptualmente, y es una manera fácil de crear errores (.innerHTML tiene el mismo problema)

Mucho mejor usar los métodos de manipulación DOM seguros y amigables con DOM

annakata
fuente
39
-1, modifica absolutamente el DOM. Todo lo demás está bien. Si bien entiendo la necesidad de depender de la estructura y los métodos que pueden evitar daños, este puede ser un caso de tirar al bebé con el agua del baño.
cgp
77
FireBug no es una verdadera representación del DOM. Es el intento de Mozilla de analizar HTML en un DOM. Puede tener un aspecto HTML totalmente roto en la vista DOM de Firebug.
FlySwat
8
El DOM es la estructura de datos utilizada para representar la página y, como tal, es el alfa y el omega de lo que el usuario ve en la página. Tienes razón en que HTML! = DOM, pero es irrelevante para la pregunta de si DW modifica o no el DOM. Si DW no modificó el DOM, no verá la pantalla; eso es cierto para todos los navegadores y siempre será así siempre que el DOM sea lo que se usa para representar la página.
cgp
8
"DW se ejecuta donde se encuentra" : no siempre es una desventaja, de hecho, podría considerarse una ventaja para ciertas cosas, por ejemplo, agregar elementos de script (en realidad es lo único para lo que usaría DW, e incluso entonces lo pensaría dos veces) .
nnnnnn
77
@RicardoRivaldo Sí, lo hacen, si document.writese llama después de que el documento haya terminado de cargarse
Izkata
124

En realidad no hay nada de malo document.write, per se. El problema es que es realmente fácil usarlo mal. Demasiado, incluso.

En términos de proveedores que suministran código de análisis (como Google Analytics), en realidad es la forma más fácil para que distribuyan dichos fragmentos

  1. Mantiene los guiones pequeños
  2. No tienen que preocuparse por anular eventos de carga ya establecidos o incluir la abstracción necesaria para agregar eventos de carga de manera segura
  3. Es extremadamente compatible

Siempre y cuando no intentes usarlo después de que el documento se haya cargado ,document.writeno es inherentemente malo, en mi humilde opinión.

Peter Bailey
fuente
3
document.write hace cosas realmente horribles a los analizadores html, y solo es "extremadamente compatible" en casos simples.
olliej
27
¿Te gusta la inserción de una etiqueta de análisis? Eso es, después de todo, parte de la pregunta original. Y por extremadamente compatible, me refiero solo a la compatibilidad del navegador en bruto para el método document.write.
Peter Bailey
Cualquier cosa que funcione con las últimas versiones de Chrome / IE / Safari / Opera / FireFox se considera compatible.
Pacerier
2
¿Anular eventos de carga? ¿Y para qué sirve addEventListener?
m93a
Chrome no ejecutará document.writeinvocaciones que inserten un script cuando se cumplan ciertas condiciones.
Flimm
44

Otro uso legítimo de document.writeproviene del ejemplo 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>

También he visto la misma técnica para usar json2.js JSON parse / stringify polyfill ( necesario para IE7 y versiones posteriores ).

<script>window.JSON || document.write('<script src="json2.js"><\/script>')</script>
Kevin Hakanson
fuente
11
No es un mal uso aquí, pero sigue siendo "mejor" usar las funciones de manipulación DOM, incluso Google lo hace para Google Analytics. Fragmento está aquí .
BMiner
8
@BMiner si inserta un scriptelemento a través de la manipulación DOM, ¿se carga sincrónicamente? A menos que lo sea, no es un reemplazo.
John Dvorak
2
@ JanDvorak - Buen punto; Cuando se utilizan manipulaciones DOM, los navegadores generalmente cargan el script de forma asincrónica. Puede usar el onloadevento DOM para determinar cuándo la secuencia de comandos cargada asincrónicamente está disponible para su uso.
BMiner
1
@ JanDvorak Se carga sincrónicamente si no es externo (no tiene src) . De lo contrario, se ejecutará "lo antes posible", de forma asincrónica.
Oriol
1
Esto todavía puede romperse, ya que Chrome se negará deliberadamente a ejecutar document.writellamadas que inserten <script>etiquetas si el usuario está en una conexión 2G. Ver developers.google.com/web/updates/2016/08/…
Flimm
42

Puede bloquear tu página

document.writesolo funciona mientras se carga la página; Si lo llama después de que la página haya terminado de cargarse, sobrescribirá toda la página.

Esto efectivamente significa que debe llamarlo desde un bloque de secuencia de comandos en línea, y eso evitará que el navegador procese partes de la página que sigue. Los scripts y las imágenes no se descargarán hasta que finalice el bloque de escritura.

Sean McMillan
fuente
32

Pro:

  • Es la forma más fácil de incrustar contenido en línea desde un script externo (a su host / dominio).
  • Puede sobrescribir todo el contenido en un marco / iframe. Solía ​​usar esta técnica mucho para menús / piezas de navegación antes de que las técnicas más modernas de Ajax estuvieran ampliamente disponibles (1998-2002).

Estafa:

  • Se serializa el motor de renderizado para pausar hasta que se carga dicho script externo, lo que podría llevar mucho más tiempo que un script interno.
  • Por lo general, se usa de tal manera que el script se coloca dentro del contenido, lo que se considera de mala forma.
Rastreador1
fuente
3
Hay más contras que eso. Por ejemplo, Google Chrome se negará a ejecutar document.writeque crea <script>etiquetas en ciertas circunstancias. developers.google.com/web/updates/2016/08/…
Flimm
@Flimm vale la pena señalar, su comentario es más de 8 años después de mi respuesta y esto casi 3 años después. Sí, hay otras desventajas ... y me sorprendería si document.write en sí no desaparece ... así como posiblemente otras interfaces altamente abusadas.
Rastreador1
10

Este es mi valor de dos peniques, en general no debe usarlo document.writepara levantar objetos pesados, pero hay una instancia en la que definitivamente es útil:

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

Descubrí esto recientemente tratando de crear una galería deslizante AJAX. Creé dos divs anidados, y apliqué width/ heighty overflow: hiddenal exterior <div>con JS. Esto fue para que en el caso de que el navegador tuviera JS deshabilitado, el div flotaría para acomodar las imágenes en la galería, una degradación agradable y elegante.

La cosa es, como con el artículo anterior, este secuestro JS del CSS no se activó hasta que la página se cargó, causando un destello momentáneo a medida que se cargaba el div. Entonces necesitaba escribir una regla CSS, o incluir una hoja, a medida que se cargaba la página.

Obviamente, esto no funcionará en XHTML, pero dado que XHTML parece ser algo así como un pato muerto (y se representa como etiqueta de sopa en IE), podría valer la pena reevaluar su elección de DOCTYPE ...

sunwukung
fuente
7

Sobrescribe el contenido de la página, que es la razón más obvia, pero no lo llamaría "malo".

Simplemente no tiene mucho uso a menos que esté creando un documento completo usando JavaScript, en cuyo caso puede comenzar con document.write.

Aun así, en realidad no estás aprovechando el DOM cuando usas document.write, solo estás volcando una gota de texto en el documento, así que diría que es una mala forma.

aleemb
fuente
2
Una aclaración: document.write inserta contenido en la página, no los sobrescribe.
Peter Dolberg
55
@ Peter, sobrescribe el contenido si lo llama después de cargar el documento. Supongo que eso es lo que significa aleemb.
Matthew Crumley
2
¿Está sugiriendo que en su lugar se deben construir manualmente los nodos DOM individuales en el código en lugar de simplemente hacer algo como div.innerHTML = "<label for='MySelect'>Choose One</label><select id='MySelect'><option value='foo' selected=''>foo</option><option value='bar'>bar</option></select>";? Parece que produciría un montón de código innecesario y menos legible. También es exactamente lo contrario del enfoque que John Resig y otros desarrolladores de JS defienden.
Lèse majesté
7

Rompe las páginas usando la representación XML (como las páginas XHTML).

Mejor : algunos navegadores vuelven a la representación HTML y todo funciona bien.

Probable : algunos navegadores deshabilitan la función document.write () en modo de representación XML.

Lo peor : algún navegador generará un error XML siempre que use la función document.write ().

Vincent Robert
fuente
6

La parte superior de mi cabeza:

  1. document.writedebe usarse en la carga de la página o la carga del cuerpo. Entonces, si desea usar el script en cualquier otro momento para actualizar el documento de contenido de su página, la escritura es prácticamente inútil.

  2. Técnicamente document.writesolo actualizará páginas HTML, no XHTML / XML. IE parece ser bastante indulgente con este hecho, pero otros navegadores no lo serán.

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

Brendan
fuente
99
IE es indulgente porque no es compatible con XHTML. Si / cuando lo hacen, document.write probablemente dejará de funcionar (solo en XHTML, por supuesto).
Matthew Crumley
2
XHTML es irrelevante en la web. Páginas incluso con un tipo de documento XHTML estrictos no se tratan en la actualidad como XML en ese sentido, los desarrolladores de navegadores no lo hacen los autores de páginas de confianza que mucho.
RobG
3

Infracción del navegador

.writese considera una violación del navegador, ya que impide que el analizador muestre la página. El analizador recibe el mensaje de que el documento se está modificando; por lo tanto, se bloquea hasta que JS haya completado su proceso. Solo en este momento se reanudará el analizador.

Actuación

La mayor consecuencia de emplear tal método es un rendimiento reducido. El navegador tardará más en cargar el contenido de la página. La reacción adversa en el tiempo de carga depende de lo que se escriba en el documento. No verá mucha diferencia si está agregando una <p>etiqueta al DOM en lugar de pasar un conjunto de 50 referencias a bibliotecas de JavaScript (algo que he visto en el código de trabajo y resultó en un retraso de 11 segundos - de Por supuesto, esto también depende de su hardware).

Con todo, es mejor mantenerse alejado de este método si puede evitarlo.

Para obtener más información, vea Intervenir contra document.write ()

Arielle Adams
fuente
3

Según el análisis realizado por Lighthouse Audit de Google-Chrome Dev Tools ,

Para los usuarios con conexiones lentas, las secuencias de comandos externas inyectadas dinámicamente document.write()pueden retrasar la carga de la página en decenas de segundos.

ingrese la descripción de la imagen aquí

Sudip Bhandari
fuente
2
  • Una razón simple por la cual document.writees una mala práctica es que no puede encontrar un escenario en el que no pueda encontrar una mejor alternativa.
  • Otra razón es que se trata de cadenas en lugar de objetos (es muy primitivo).
  • Solo se agrega a los documentos.
  • No tiene nada de bello, por ejemplo, el patrón MVC (Modelo-Vista-Controlador) .
  • Es mucho más poderoso presentar contenido dinámico con ajax + jQuery o angularJS .
Anders Lindén
fuente
En cuanto a tu primera viñeta, ¿cómo vas a resolver lo que @sunwukung describe en su respuesta anterior? Estoy de acuerdo en que podría resolverlo con manipulaciones DOM, pero a medida que avanzan las manipulaciones DOM, es difícil evitar FUOC a veces sin document.write.
bert bruynooghe
¿FUOC ya es un problema?
Anders Lindén
1

Uno puede pensar en document.write () (y .innerHTML) como la evaluación de una cadena de código fuente. Esto puede ser muy útil para muchas aplicaciones. Por ejemplo, si obtiene código HTML como una cadena de alguna fuente, es útil simplemente "evaluarlo".

En el contexto de Lisp, la manipulación DOM sería como manipular una estructura de lista, por ejemplo, crear la lista (naranja) haciendo:

(cons 'orange '())

Y document.write () sería como evaluar una cadena, por ejemplo, crear una lista evaluando una cadena de código fuente como esta:

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

Lisp también tiene la capacidad muy útil de crear código usando la manipulación de listas (como usar el "estilo DOM" para crear un árbol de análisis JS). Esto significa que puede crear una estructura de lista utilizando el "estilo DOM", en lugar del "estilo de cadena", y luego ejecutar ese código, por ejemplo, así:

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

Si implementa herramientas de codificación, como simples editores en vivo, es muy útil tener la capacidad de evaluar rápidamente una cadena, por ejemplo, usando document.write () o .innerHTML. Lisp es ideal en este sentido, pero también puedes hacer cosas muy interesantes en JS, y muchas personas lo están haciendo, como http://jsbin.com/

Mikael Kindborg
fuente
1

Las desventajas de document.write dependen principalmente de estos 3 factores:

a) Implementación

Document.write () se usa principalmente para escribir contenido en la pantalla tan pronto como se necesita ese contenido. Esto significa que ocurre en cualquier lugar, ya sea en un archivo JavaScript o dentro de una etiqueta de script dentro de un archivo HTML. Con la etiqueta de script colocada en cualquier lugar dentro de dicho archivo HTML, es una mala idea tener declaraciones document.write () dentro de bloques de script que se entrelazan con HTML dentro de una página web.

b) Representación

El código bien diseñado en general tomará cualquier contenido generado dinámicamente, lo almacenará en la memoria, lo seguirá manipulando a medida que pase por el código antes de que finalmente se escupe en la pantalla. Por lo tanto, para reiterar el último punto en la sección anterior, la representación del contenido en el lugar puede procesarse más rápido que otro contenido en el que se puede confiar, pero puede no estar disponible para el otro código que a su vez requiere que el contenido se procese para su procesamiento. Para resolver este dilema, debemos deshacernos de document.write () e implementarlo de la manera correcta.

c) Manipulación imposible

Una vez que está escrito, está hecho y terminado. No podemos volver a manipularlo sin aprovechar el DOM.

usuario3167857
fuente
1

No creo que usar document.write sea una mala práctica en absoluto. En palabras simples, es como un alto voltaje para personas sin experiencia. Si lo usa de la manera incorrecta, se cocina. Hay muchos desarrolladores que han utilizado este y otros métodos peligrosos al menos una vez, y realmente nunca profundizan en sus fallas. En cambio, cuando algo sale mal, simplemente se rescatan y usan algo más seguro. Esos son los que hacen tales declaraciones sobre lo que se considera una "mala práctica".

Es como formatear un disco duro, cuando necesita eliminar solo unos pocos archivos y luego decir "formatear el disco es una mala práctica".

Edgars WEBHAUS
fuente
-3

Creo que el mayor problema es que cualquier elemento escrito a través de document.write se agrega al final de los elementos de la página. Raramente es el efecto deseado con diseños de página modernos y AJAX. (debe tener en cuenta que los elementos en el DOM son temporales, y cuando se ejecuta el script puede afectar su comportamiento).

Es mucho mejor establecer un elemento de marcador de posición en la página y luego manipular su innerHTML.

BnWasteland
fuente
15
Esto no es verdad. document.write no agrega el contenido al final de la página como si fuera un anexo. Están escritos en su lugar.
Peter Bailey
1
@ Peter Bailey, sé que este es un hilo viejo, pero realmente no debería ser rechazado. si se agrega o no depende de si document.write () se ejecuta en línea mientras se carga la página. Si se llama desde una función después de que se carga la página, el primer document.write () reemplazará todo el cuerpo y se agregarán llamadas posteriores.
Octopus
3
@ Octopus Sí, pero eso es circunstancial. Se agrega en ese escenario solo porque hay un documento nuevo. Todavía no es exacto decir "document.write () appends". Sí, es una vieja respuesta y un viejo voto negativo, pero aún lo mantengo.
Peter Bailey
Está bien. Hablé con imprecisión. Lo habría editado hace mucho tiempo, pero hay una respuesta mucho mejor arriba. Sin embargo, quisiera señalar que "escrito en el lugar" es igualmente impreciso.
BnWasteland