Por que document.write é considerado uma “má prática”?

363

Eu sei que document.writeé considerado má prática; e espero compilar uma lista de motivos para enviar a um fornecedor terceirizado sobre o motivo pelo qual eles não devem usar document.writenas implementações de seu código de análise.

Inclua document.writeabaixo o motivo para reivindicar como uma má prática.

FlySwat
fonte

Respostas:

243

Alguns dos problemas mais sérios:

  • document.write (doravante DW) não funciona em XHTML

  • O DW não modifica diretamente o DOM, impedindo mais manipulação (tentando encontrar evidências disso, mas na melhor das hipóteses, situacional)

  • O DW executado após o carregamento da página substituirá a página ou gravará uma nova página ou não funcionará

  • O DW executa onde encontrado: não pode injetar em um determinado ponto do nó

  • O DW está efetivamente escrevendo texto serializado, que não é o modo como o DOM funciona conceitualmente e é uma maneira fácil de criar bugs (.innerHTML tem o mesmo problema)

Muito melhor usar os métodos de manipulação de DOM seguros e amigáveis ​​ao DOM

annakata
fonte
39
-1, absolutamente modifica o DOM. Tudo o resto está bem. Embora eu compreenda o desejo de depender da estrutura e dos métodos que podem impedi-lo de causar danos, esse pode ser o caso de jogar fora o bebê com a água do banho.
Cgp
7
FireBug não é uma representação verdadeira do DOM. É a tentativa do mozilla de analisar o HTML em um DOM. Você pode ter um HTML totalmente quebrado com aparência adequada na visualização DOM do Firebug.
FlySwat 29/04/09
8
O DOM é a estrutura de dados usada para renderizar a página e, como tal, é o alfa e o ômega do que o usuário vê na página. Você está correto quanto ao HTML! = DOM, mas é irrelevante para a questão de saber se o DOM é ou não modificado pelo DW. Se o DW não modificou o DOM, você não vê a tela - isso é verdade para todos os navegadores e sempre será enquanto o DOM for usado para renderizar a página.
Cgp
8
"O DW executa onde é encontrado" - nem sempre é uma desvantagem; na verdade, pode ser considerado uma vantagem para certas coisas, por exemplo, adicionar elementos de script (na verdade, sobre a única coisa em que eu usaria o DW e, mesmo assim, pensaria duas vezes) .
Nnnnnn
7
@RicardoRivaldo Sim, eles fazem, se document.writefor chamado após o término do carregamento do documento
Izkata
124

Na verdade, não há nada de errado em document.writesi. O problema é que é realmente fácil usá-lo mal. Grosseiramente, até.

Em termos de fornecedores que fornecem código de análise (como o Google Analytics), é realmente a maneira mais fácil de distribuir esses snippets

  1. Mantém os scripts pequenos
  2. Eles não precisam se preocupar em substituir eventos de carga já estabelecidos ou em incluir a abstração necessária para adicionar eventos de carga com segurança
  3. É extremamente compatível

Contanto que você não tente usá-lo após o carregamento do documento ,document.writenão é inerentemente mau, na minha humilde opinião.

Peter Bailey
fonte
3
O document.write faz coisas realmente horríveis para os analisadores html e é apenas "extremamente compatível" em casos simples.
olliej
27
Como a inserção de uma tag de análise? Afinal, isso faz parte da pergunta original. E por extremamente compatível, quero dizer apenas o suporte bruto ao navegador para o método document.write.
31530 Peter Bailey
Qualquer coisa que funcione com as versões mais recentes do Chrome / IE / Safari / Opera / FireFox é considerada compatível.
Pacerier
2
Substituindo eventos de onload? E para que serve addEventListener?
M93a
O Chrome não executará document.writechamadas que insiram um script quando determinadas condições forem atendidas.
Flimm
44

Outro uso legítimo de document.writevem do exemplo 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>

Também vi a mesma técnica para usar o polyfill json2.js JSON parse / stringify ( necessário pelo IE7 e abaixo ).

<script>window.JSON || document.write('<script src="json2.js"><\/script>')</script>
Kevin Hakanson
fonte
11
Não é mau uso aqui, mas ainda é "melhor" usar funções de manipulação de DOM - até o Google faz isso para o Google Analytics. O snippet está aqui .
BMiner
8
@BMiner se você inserir um scriptelemento por meio da manipulação do DOM, ele será carregado de forma síncrona? A menos que seja, não é um substituto.
John Dvorak
2
@JanDvorak - Bom argumento; ao usar manipulações DOM, os navegadores geralmente carregam o script de forma assíncrona. Você pode usar o onloadevento DOM para determinar quando o script carregado de forma assíncrona está disponível para uso.
BMiner 6/06/13
11
@JanDvorak É carregado de forma síncrona se não for externo (não possui src) . Caso contrário, será executado "o mais rápido possível", de forma assíncrona.
Oriol
11
Isso ainda pode ser interrompido, pois o Chrome se recusará deliberadamente a executar document.writechamadas que inserem <script>tags se o usuário estiver em uma conexão 2G. Veja developers.google.com/web/updates/2016/08/…
Flimm
42

Pode bloquear sua página

document.writesó funciona enquanto a página está carregando; Se você chamá-lo após o carregamento da página, ele substituirá a página inteira.

Isso significa efetivamente que você deve chamá-lo a partir de um bloco de script embutido - E isso impedirá que o navegador processe partes da página a seguir. Scripts e imagens não serão baixados até que o bloco de gravação esteja concluído.

Sean McMillan
fonte
32

Pró:

  • É a maneira mais fácil de incorporar conteúdo embutido a partir de um script externo (ao seu host / domínio).
  • Você pode substituir todo o conteúdo em um quadro / iframe. Eu costumava usar essa técnica muito para peças de menu / navegação antes que as técnicas mais modernas do Ajax estivessem amplamente disponíveis (1998-2002).

Vigarista:

  • Ele serializa o mecanismo de renderização para pausar até que o script externo seja carregado, o que pode levar muito mais tempo que um script interno.
  • Geralmente, é usado de maneira que o script seja colocado no conteúdo, considerado incorreto.
Tracker1
fonte
3
Há mais contras do que isso. Por exemplo, o Google Chrome se recusará a executar document.writeque cria uma <script>tag em determinadas circunstâncias. developers.google.com/web/updates/2016/08/…
Flimm
@Limlim vale a pena notar, seu comentário é mais de 8 anos após a minha resposta e isso quase 3 anos depois. Sim, existem outros contras ... e eu ficaria surpreso se document.write em si não desaparecesse ... assim como possivelmente outras interfaces altamente abusadas.
Tracker1
10

Aqui está o meu valor de dois centavos, em geral você não deve usar document.writepara trabalhos pesados, mas há um exemplo em que é definitivamente útil:

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

Descobri isso recentemente, tentando criar uma galeria deslizante AJAX. Criei duas divs aninhadas e apliquei width/ heighte overflow: hiddenpara o exterior <div>com JS. Isso foi feito para que, no caso de o JS ter o JS desativado, a div flutuasse para acomodar as imagens na galeria - alguma degradação agradável e agradável.

O problema é que, como no artigo acima, esse sequestro de JS do CSS não entrou em ação até a página ter sido carregada, causando um flash momentâneo quando a div foi carregada. Então, eu precisava escrever uma regra CSS, ou incluir uma folha, como a página carregada.

Obviamente, isso não funcionará no XHTML, mas, como o XHTML parece um pato morto (e é processado como tag tag no IE), pode valer a pena reavaliar sua escolha do DOCTYPE ...

sunwukung
fonte
7

Ele substitui o conteúdo da página, que é o motivo mais óbvio, mas eu não chamaria de "ruim".

Ele não tem muita utilidade, a menos que você esteja criando um documento inteiro usando JavaScript. Nesse caso, você pode começar com document.write.

Mesmo assim, você não está realmente aproveitando o DOM ao usar document.write - você está apenas despejando um blob de texto no documento, então eu diria que é uma má forma.

aleemb
fonte
2
Um esclarecimento: document.write insere o conteúdo da página, não o substitui.
31840 Peter Dolberg
5
@ Peter, ele substitui o conteúdo se você o chamar depois que o documento for carregado. Acho que é isso que aleemb significa.
Matthew Crumley
2
Você está sugerindo que você deva criar manualmente os nós DOM individuais no código, em vez de fazer algo parecido 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 isso produziria muitos códigos desnecessários e menos legíveis. Também é exatamente o oposto da abordagem que John Resig e outros desenvolvedores de JS defendem.
Lèse majesté
7

Ele quebra as páginas usando a renderização XML (como páginas XHTML).

Melhor : alguns navegadores retornam à renderização HTML e tudo funciona bem.

Provável : alguns navegadores desativam a função document.write () no modo de renderização XML.

Pior : alguns navegadores acionarão um erro XML sempre que usar a função document.write ().

Vincent Robert
fonte
6

Em cima da minha cabeça:

  1. document.writeprecisa ser usado no carregamento da página ou no corpo. Portanto, se você quiser usar o script em qualquer outro momento para atualizar o conteúdo da página document.write é praticamente inútil.

  2. Tecnicamente document.write, somente as páginas HTML serão atualizadas, e não XHTML / XML. O IE parece perdoar bastante esse fato, mas outros navegadores não o serão.

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

brendan
fonte
9
O IE está perdoando porque não suporta XHTML. Se / quando o fizerem, o document.write provavelmente parará de funcionar (apenas no XHTML, é claro).
21430 Matthew Crumley
2
XHTML é irrelevante na web. Páginas Mesmo com um rigoroso doctype XHTML não são realmente tratados como XML a este respeito, os desenvolvedores do navegador não autores de páginas de confiança que muito.
RobG 27/10/2015
4

O Chrome pode bloquear document.writea inserção de um script em certos casos. Quando isso acontece, ele exibirá este aviso no console:

Um script de origem cruzada com bloqueio de analisador, ..., é chamado via document.write. Isso pode ser bloqueado pelo navegador se o dispositivo tiver uma conectividade de rede ruim.

Referências:

TrueWill
fonte
3

Violação do navegador

.writeé considerado uma violação do navegador, pois impede o analisador de renderizar a página. O analisador recebe a mensagem de que o documento está sendo modificado; portanto, ele é bloqueado até que JS conclua seu processo. Somente nesse momento o analisador será retomado.

atuação

A maior consequência de empregar esse método é o desempenho reduzido. O navegador levará mais tempo para carregar o conteúdo da página. A reação adversa no tempo de carregamento depende do que está sendo gravado no documento. Você não verá muita diferença se estiver adicionando uma <p>tag ao DOM, em vez de passar uma matriz de 50 e algumas referências a bibliotecas JavaScript (algo que eu vi no código de trabalho e resultou em um atraso de 11 segundos - de claro, isso também depende do seu hardware).

Em suma, é melhor evitar esse método, se você puder ajudá-lo.

Para obter mais informações, consulte Intervenções contra document.write ()

Arielle Adams
fonte
3

Com base na análise feita pela Lighthouse Audit do Google-Chrome Dev Tools ,

Para usuários em conexões lentas, scripts externos injetados dinamicamente via document.write()podem atrasar o carregamento da página em dezenas de segundos.

insira a descrição da imagem aqui

Sudip Bhandari
fonte
2
  • Uma razão simples por que document.writeé uma má prática é que você não pode criar um cenário em que não encontre uma alternativa melhor.
  • Outro motivo é que você está lidando com strings em vez de objetos (é muito primitivo).
  • Ele apenas anexa aos documentos.
  • Não tem nada da beleza de, por exemplo, o padrão MVC (Model-View-Controller) .
  • É muito mais poderoso apresentar conteúdo dinâmico com ajax + jQuery ou angularJS .
Anders Lindén
fonte
Quanto à sua primeira bala, como você vai resolver o que @sunwukung descreve em sua resposta acima? Concordo que você poderia resolvê-lo com manipulações DOM, mas, como as manipulações DOM, é difícil evitar o FUOC às vezes sem document.write.
18717 Jan 16
O FUOC é mais um problema?
Anders Lindén
1

Pode-se pensar em document.write () (e .innerHTML) como avaliar uma sequência de código-fonte. Isso pode ser muito útil para muitos aplicativos. Por exemplo, se você obtiver o código HTML como uma sequência de alguma fonte, é útil apenas "avaliá-lo".

No contexto do Lisp, a manipulação do DOM seria como manipular uma estrutura de lista, por exemplo, crie a lista (laranja) fazendo:

(cons 'orange '())

E document.write () seria como avaliar uma string, por exemplo, crie uma lista avaliando uma string de código-fonte como esta:

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

O Lisp também tem a capacidade muito útil de criar código usando manipulação de lista (como usar o "estilo DOM" para criar uma árvore de análise JS). Isso significa que você pode criar uma estrutura de lista usando o "estilo DOM", em vez do "estilo string", e depois executar esse código, por exemplo:

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

Se você implementar ferramentas de codificação, como editores simples ao vivo, é muito útil ter a capacidade de avaliar rapidamente uma string, por exemplo, usando document.write () ou .innerHTML. Lisp é ideal nesse sentido, mas você pode fazer coisas muito legais também em JS, e muitas pessoas estão fazendo isso, como http://jsbin.com/

Mikael Kindborg
fonte
1

As desvantagens de document.write dependem principalmente desses três fatores:

a) Implementação

O document.write () é usado principalmente para gravar conteúdo na tela assim que esse conteúdo for necessário. Isso significa que isso acontece em qualquer lugar, em um arquivo JavaScript ou dentro de uma tag de script em um arquivo HTML. Com a tag de script sendo colocada em qualquer lugar dentro de um arquivo HTML, é uma má idéia ter instruções document.write () dentro de blocos de script entrelaçados com HTML dentro de uma página da web.

b) Renderização

Código bem projetado, em geral, pega qualquer conteúdo gerado dinamicamente, armazena-o na memória, continua manipulando-o à medida que passa pelo código antes que ele finalmente seja cuspido na tela. Portanto, para reiterar o último ponto da seção anterior, a renderização de conteúdo no local pode renderizar mais rapidamente do que outros conteúdos confiáveis, mas pode não estar disponível para o outro código que, por sua vez, exige que o conteúdo seja renderizado para processamento. Para resolver esse dilema, precisamos nos livrar do document.write () e implementá-lo da maneira certa.

c) Manipulação impossível

Uma vez escrito, está pronto e terminado. Não podemos voltar a manipulá-lo sem tocar no DOM.

user3167857
fonte
1

Não acho que usar document.write seja uma prática ruim. Em palavras simples, é como uma alta voltagem para pessoas inexperientes. Se você usá-lo da maneira errada, você cozinha. Existem muitos desenvolvedores que usaram esse e outros métodos perigosos pelo menos uma vez, e eles nunca se aprofundam em suas falhas. Em vez disso, quando algo dá errado, eles simplesmente saem e usam algo mais seguro. Esses são os que fazem tais afirmações sobre o que é considerado uma "má prática".

É como formatar um disco rígido, quando você precisa excluir apenas alguns arquivos e dizer "formatar a unidade é uma prática ruim".

Edgars WEBHAUS
fonte
-3

Eu acho que o maior problema é que quaisquer elementos escritos via document.write são adicionados ao final dos elementos da página. Isso raramente é o efeito desejado com layouts de páginas modernos e AJAX. (você deve ter em mente que os elementos no DOM são temporais e quando o script é executado pode afetar seu comportamento).

É muito melhor definir um elemento de espaço reservado na página e depois manipulá-lo innerHTML.

BnWasteland
fonte
15
Isso não é verdade. document.write não adiciona o conteúdo ao final da página como se fosse um anexo. Eles estão escritos no lugar.
31530 Peter Bailey
11
@ Peter Bailey, eu sei que este é um tópico antigo, mas realmente isso não deve ser prejudicado. se ele anexa ou não, depende se document.write () é executado inline enquanto a página está sendo carregada. Se for chamado de uma função após o carregamento da página, o primeiro document.write () substituirá o corpo inteiro e as chamadas subsequentes serão anexadas a ele.
Octopus
3
@ Octopus Sim, mas isso é circunstancial. Ele é anexado nesse cenário apenas porque há um documento novo. Ainda não é correto dizer "document.write () anexa". Sim, é uma resposta antiga e um voto negativo antigo, mas eu ainda a sustento.
Peter Bailey
Está bem. Eu falei imprecisa. Eu o teria editado há muito tempo, mas há uma resposta muito melhor acima. Eu apontaria que "escrito no lugar" é igualmente impreciso.
BnWasteland