Como exatamente <script adiar = "adiar"> funciona?

208

Eu tenho alguns <script> elementos, e o código em alguns deles depende do código em outros <script>elementos. Vi que o deferatributo pode ser útil aqui, pois permite que os blocos de código sejam adiados na execução.

Para testá-lo, executei isso no Chrome: http://jsfiddle.net/xXZMN/ .

<script defer="defer">alert(2);</script>
<script>alert(1)</script>
<script defer="defer">alert(3);</script>

No entanto, ele alerta 2 - 1 - 3. Por que não alerta 1 - 2 - 3?

pimvdb
fonte
2
Talvez confira este artigo . E, como sempre, o IE tem sua própria opinião sobre o que significa algo e decidiu carregar o script primeiro, mas adia a execução até que o corpo seja carregado (normalmente).
22411 Brad Christie
Obrigado, no entanto, a página de teste tem um resultado diferente no Chrome: websiteoptimization.com/speed/tweak/defer/test . A captura de tela mostra como eu esperaria, enquanto o Chrome parece executar primeiro o adiado.
Pimvdb 9/03/11
1
Acho que você encontrará a definição de adiamento do IE, corresponde à intenção de adiamento do W3C na especificação de nível 1 do DOM.
usar o seguinte código
41
Como Alohci já apontou em sua resposta, de acordo com o Padrão HTML defer só é válido quando especificado src. Esse pode ser o motivo pelo qual seu exemplo não funcionou conforme o esperado na maioria dos navegadores.
Pankrat
2
@Pankrat História verdadeira! Tente jsfiddle.net/xXZMN/50 Testado no Firefox24
m93a 22-13

Respostas:

51

ATUALIZAÇÃO: 19/02/2016

Considere esta resposta desatualizada. Consulte outras respostas nesta publicação para obter informações relevantes para a versão mais recente do navegador.


Basicamente, o adiamento diz ao navegador para aguardar "até que esteja pronto" antes de executar o javascript nesse bloco de scripts. Geralmente, isso ocorre depois que o DOM termina o carregamento e o documento.readyState == 4

O atributo defer é específico para o Internet Explorer. No Internet Explorer 8, no Windows 7, o resultado que estou vendo na sua página de teste do JS Fiddle é 1 - 2 - 3.

Os resultados podem variar de navegador para navegador.

http://msdn.microsoft.com/en-us/library/ms533719(v=vs.85).aspx

Ao contrário da crença popular, o IE segue os padrões com mais frequência do que as pessoas deixam transparecer. Na verdade, o atributo "adiar" é definido na especificação do nível 1 do DOM http://www.w3.org/TR/REC-DOM-Level-1/level -one-html.html

A definição de adiamento do W3C: http://www.w3.org/TR/REC-html40/interact/scripts.html#adef-defer :

"Quando definido, esse atributo booleano fornece uma dica ao agente do usuário de que o script não irá gerar nenhum conteúdo do documento (por exemplo, nenhum" document.write "em javascript) e, portanto, o agente do usuário pode continuar analisando e processando".

Mark At Ramp51
fonte
8
@ MarkAtRamp51 - Se sua resposta estiver desatualizada, você deve editá-la em vez de reclamar de votos negativos nos comentários de outras respostas. Votos negativos são para respostas que "não são úteis".
Christian ConkleMar
10
@ChristianConkle Agradeço a lição de etiqueta, no entanto, as outras respostas aqui estão atualizadas. Eu estava abordando o fato de que a resposta errada não foi selecionada no momento em que a pergunta foi feita. Talvez você deva policiar as pessoas que divulgam falsas avaliações sobre a comunidade selecionar indevidamente respostas, em vez de as pessoas tentarem lembrar às pessoas que as coisas mudam com o tempo e o contexto é importante. Não vejo valor em remover minha resposta, pois as informações históricas também são valiosas.
usar o seguinte código
3
"Não vejo valor em remover minha resposta, pois as informações históricas também são valiosas". Nesse caso, que tal adicionar uma observação no início, apontando que ela se aplica apenas ao pré-HTML5 e depois vinculando-a ao "correto" ( resposta)? Isso deve poupar muitos problemas (falar como um cara que também recebeu uma resposta "errada" uma vez e foi "pressionado pelos colegas" para, eventualmente, mudar isso).
mgibsonbr
3
@ Leo não deve ser sinalizado então? Pesquisando "html5 adiar script", este é o terceiro resultado no google. Essa resposta está fornecendo a muitos usuários uma definição desatualizada e incorreta. (A definição atual: "Indica que o agente do usuário pode adiar o processamento do script. Consulte a definição de atributo de adiamento no HTML 4.0.").
Malavos
2
@ MarkAtRamp51 Acho que você deve atualizar sua resposta. Quem encontrar essa pergunta e sua resposta não reconhecerá suas informações históricas. Parece que é a resposta correta hoje. É assim que a internet funciona. Portanto, edite sua resposta, observe que ela estava correta uma vez e consulte a resposta correta.
Juuro #
167

Alguns trechos da especificação HTML5: http://w3c.github.io/html/semantics-scripting.html#element-attrdef-script-async

Os atributos defer e async não devem ser especificados se o atributo src não estiver presente.


Existem três modos possíveis que podem ser selecionados usando esses atributos [assíncrono e adiado]. Se o atributo async estiver presente, o script será executado de forma assíncrona, assim que estiver disponível. Se o atributo async não estiver presente, mas o atributo defer estiver presente, o script será executado quando a página terminar de analisar. Se nenhum atributo estiver presente, o script será buscado e executado imediatamente, antes que o agente continue analisando a página.


Os detalhes exatos de processamento para esses atributos são, por razões históricas, um tanto não triviais, envolvendo vários aspectos do HTML. Os requisitos de implementação são, portanto, necessariamente espalhados por toda a especificação. Os algoritmos abaixo (nesta seção) descrevem o núcleo desse processamento, mas esses algoritmos referenciam e são referenciados pelas regras de análise para tags de início e fim de script em HTML, conteúdo estrangeiro e XML, as regras para o document.write (), o tratamento de scripts etc.


Se o elemento tiver um atributo src, e o elemento tiver um atributo defer, e o elemento tiver sido marcado como "inserido pelo analisador", e o elemento não tiver um atributo assíncrono:

O elemento deve ser adicionado ao final da lista de scripts que serão executados quando o documento concluir a análise associada ao documento do analisador que criou o elemento.

Alohci
fonte
37
Talvez minha resposta aqui impeça as pessoas de votarem na minha resposta, devido ao seu comentário não útil. A resposta aceita não está errada, a resposta é diferente, porque no início de 2011 a especificação do HTML5 era menos relevante para os navegadores da Web convencionais do que atualmente. Essa resposta pode ser melhor daqui para frente, mas a resposta aceita não é ERRADA por nenhum padrão.
Mark No Ramp51
3
Embora seja útil saber o que as especificações dizem, acontece que alguns navegadores como o IE <9 implementam defermal . Se você usar defer, não poderá confiar na execução dos arquivos de script em alguns navegadores.
Flimm
2
@ Limlim Não apenas o IE, parece que a ordem de execução também não é garantida no Firefox .
Franklin Yu
A primeira citação não é mais válida, certo? Agora eu posso ler o seguinte: "O atributo não deve ser especificado se o atributo src não estiver presente ou se o script não for um script clássico.". E um script clássico também é um sem src = "".
Félix Sanz
158

A resposta real é: porque você não pode confiar no adiamento.

No conceito, adiar e assíncrono diferem da seguinte forma:

assíncrono permite que o script seja baixado em segundo plano sem bloquear. Em seguida, no momento em que termina o download, a renderização é bloqueada e esse script é executado. A renderização é retomada quando o script é executado.

adiar faz o mesmo, exceto reivindicações para garantir que os scripts sejam executados na ordem em que foram especificados na página e que serão executados após o término da análise do documento. Portanto, alguns scripts podem terminar o download e aguardar os scripts que foram baixados mais tarde, mas que apareceram antes deles.

Infelizmente, devido ao que é realmente uma briga de gato de padrões, a definição de adiamento varia de especificação para especificação, e mesmo nas especificações mais recentes não oferece uma garantia útil. Como as respostas aqui e esse problema demonstram, os navegadores implementam o adiamento de maneira diferente:

  • Em certas situações, alguns navegadores têm um bug que causa a falha deferde execução dos scripts.
  • Alguns navegadores atrasam o DOMContentLoadedevento até depois que os deferscripts foram carregados, e outros não.
  • Alguns navegadores obedecem defera <script>elementos com código embutido e sem srcatributo, e outros o ignoram.

Felizmente, a especificação especifica pelo menos que as substituições assíncronas sejam adiadas. Assim, você pode tratar todos os scripts como assíncronos e obter uma ampla variedade de suporte ao navegador da seguinte forma:

<script defer async src="..."></script>

98% dos navegadores em uso no mundo todo e 99% nos EUA evitarão o bloqueio com essa abordagem.

(Se você precisar esperar até que o documento termine de analisar, ouça o evento do DOMContentLoadedevento ou use a .ready()função útil do jQuery . Você desejaria fazer isso de qualquer maneira para voltar normalmente aos navegadores que não são implementados defer.)

Chris Moschini
fonte
13
Obrigado, sua resposta foi a mais útil para mim!
Mark12 dez12
5
Eu acredito que isso está incorreto. O benefício do adiamento é que ele não é executado até que a análise da página seja concluída. Esta página tem um bom visual para explicar a diferença entre async e defer: peter.sh/experiments/...
tinkerr
1
@tinkerr No conceito, você está correto; na prática, isso não se mostra verdadeiro. Como não é implementada de forma consistente, a garantia de sequência não é universal e, portanto, não é uma garantia. Ao implementar algo, você se preocupa com a execução. A intenção do design é atraente, mas não particularmente útil.
Chris Moschini
Só queria ressaltar que o Opera suporta o deferatributo desde a versão 15 , lançada em 2 de junho de 2013 .
1
@VikasBansal Para navegadores mais antigos que não suportam assíncrono - ou seja, o IE mais antigo.
Chris Moschini
13

defersó pode ser usado na <script>tag para inclusão de script externo . Portanto, recomenda-se que seja usado nas <script>tags <head>-seção.

Rajesh Paul
fonte
8

O atributo adiar funciona apenas com a tag scripts com src. Foi encontrada uma maneira de imitar o adiamento de scripts embutidos. Use o evento DOMContentLoaded.

<script defer src="external-script.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
    // Your inline scripts which uses methods from external-scripts.
});
</script>

Isso ocorre porque o evento DOMContentLoaded é acionado após o adiamento de scripts atribuídos ser completamente carregado.

Bijoy Anupam
fonte
6

O atributo defer é apenas para scripts externos (só deve ser usado se o atributo src estiver presente).

Soumitra
fonte
4

Veja este excelente artigo Mergulhe nas águas turvas do carregamento de scripts pelo desenvolvedor do Google Jake Archibald escrito em 2013.

Citando a seção relevante desse artigo:

Adiar

<script src="//other-domain.com/1.js" defer></script>
<script src="2.js" defer></script>

Spec diz : Faça o download juntos, execute em ordem imediatamente antes de DOMContentLoaded. Ignore "adiar" em scripts sem "src".

O IE <10 diz : Eu posso executar o 2.js na metade da execução do 1.js. Isso não é divertido?

Os navegadores em vermelho dizem : não tenho idéia do que é esse "adiamento", vou carregar os scripts como se não estivessem lá.

Outros navegadores dizem : Ok, mas talvez eu não ignore "adiar" em scripts sem "src".

(Acrescentarei que as versões anteriores do Firefox acionam o DOMContentLoaded antes que os deferscripts terminem de ser executados, de acordo com este comentário .)

Os navegadores modernos parecem oferecer suporte asyncadequado, mas você precisa estar bem com os scripts esgotados e possivelmente antes do DOMContentLoaded.

Flimm
fonte
1

Este atributo booleano é definido para indicar a um navegador que o script deve ser executado após a análise do documento. Como esse recurso ainda não foi implementado por todos os outros principais navegadores, os autores não devem assumir que a execução do script será realmente adiada. Nunca chame document.write () a partir de um script de adiamento (desde o Gecko 1.9.2, isso acabará com o documento). O atributo defer não deve ser usado em scripts que não possuem o atributo src. Desde o Gecko 1.9.2, o atributo defer é ignorado em scripts que não possuem o atributo src. No entanto, no Gecko 1.9.1, mesmo scripts em linha são adiados se o atributo defer estiver definido.

adiar trabalha com chrome, firefox, ou seja,> 7 e Safari

ref: https://developer.mozilla.org/en-US/docs/HTML/Element/script

s-sharma
fonte
0

O atributo defer é um atributo booleano.

Quando presente, especifica que o script é executado quando a página termina de analisar.

Nota: O atributo defer é apenas para scripts externos (deve ser usado apenas se o atributo src estiver presente).

Nota: Existem várias maneiras de executar um script externo:

Se o assíncrono estiver presente: O script é executado de forma assíncrona com o restante da página (o script será executado enquanto a página continua a análise) Se o assíncrono não estiver presente e o adiamento estiver presente: O script será executado quando a página terminar de analisar Se nem assíncrono ou adiado está presente: o script é buscado e executado imediatamente, antes que o navegador continue analisando a página

srikanth_k
fonte