¿Cómo funciona exactamente <script defer = "defer">?

208

Tengo algunos <script>elementos, y el código en algunos de ellos depende del código en otros <script>elementos. Vi que el deferatributo puede ser útil aquí ya que permite que los bloques de código se pospongan en la ejecución.

Para probarlo, ejecuté esto en Chrome: http://jsfiddle.net/xXZMN/ .

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

Sin embargo, alerta 2 - 1 - 3. ¿Por qué no alerta 1 - 2 - 3?

pimvdb
fuente
2
Tal vez mira este artículo . Y, como siempre, IE tiene su propia opinión sobre lo que significa algo y decidió cargar el script primero pero retrasar la ejecución hasta que se cargue el cuerpo (normalmente).
Brad Christie
Gracias, sin embargo, la página de prueba tiene un resultado diferente en Chrome: websiteoptimization.com/speed/tweak/defer/test . La captura de pantalla muestra cómo lo esperaría, mientras que Chrome parece ejecutar primero el diferido.
pimvdb
1
Creo que la definición de aplazamiento del IE coincide con la intención del aplazamiento del W3C en la especificación DOM Nivel 1.
Mark At Ramp51
41
Como Alohci ya señaló en su respuesta, de acuerdo con el Estándar HTML defer solo es válido al especificar src. Esta podría ser una razón por la cual su ejemplo no funcionó como se esperaba en la mayoría de los navegadores.
Pankrat
2
@Pankrat ¡La verdadera historia! Pruebe jsfiddle.net/xXZMN/50 Probado en Firefox24
m93a

Respuestas:

51

ACTUALIZADO: 19/02/2016

Considere esta respuesta desactualizada. Consulte otras respuestas en esta publicación para obtener información relevante para la versión más nueva del navegador.


Básicamente, aplazar le dice al navegador que espere "hasta que esté listo" antes de ejecutar el javascript en ese bloque de script. Por lo general, esto ocurre una vez que el DOM ha terminado de cargar y document.readyState == 4

El atributo de aplazamiento es específico de Internet Explorer. En Internet Explorer 8, en Windows 7, el resultado que veo en su página de prueba de JS Fiddle es 1 - 2 - 3.

Los resultados pueden variar de un navegador a otro.

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

Contrariamente a la creencia popular, IE sigue los estándares con más frecuencia de lo que la gente dice, en realidad el atributo "diferir" se define en la especificación DOM Nivel 1 http://www.w3.org/TR/REC-DOM-Level-1/level -one-html.html

La definición de aplazamiento del W3C: http://www.w3.org/TR/REC-html40/interact/scripts.html#adef-defer :

"Cuando se establece, este atributo booleano proporciona una pista al agente de usuario de que el script no generará ningún contenido del documento (por ejemplo, no" document.write "en javascript) y, por lo tanto, el agente de usuario puede continuar analizando y procesando".

Mark At Ramp51
fuente
8
@ MarkAtRamp51: si su respuesta está desactualizada, debe editarla en lugar de quejarse de votos negativos en los comentarios sobre otras respuestas. Los votos negativos son para respuestas que "no son útiles".
Christian Conkle
10
@ ChristianConkle Aprecio la lección de etiqueta, sin embargo, las otras respuestas aquí están actualizadas. Me refería al hecho de que no se seleccionó la respuesta incorrecta en el momento en que se hizo la pregunta. Tal vez debería vigilar a las personas que difunden evaluaciones falsas sobre la comunidad que selecciona las respuestas de manera incorrecta, en lugar de tratar de recordarles a las personas que las cosas cambian con el tiempo y que el contexto es importante. No veo valor en eliminar mi respuesta ya que la información histórica también es valiosa.
Mark At Ramp51
3
"No veo valor en eliminar mi respuesta, ya que la información histórica también es valiosa". En ese caso, ¿qué tal si agregamos una nota al principio señalando que solo se aplica a pre-HTML5 y luego vinculando a la "correcta" ( actualizado) respuesta? Eso debería ahorrarle muchos problemas (hablar como un tipo que también tuvo una respuesta "incorrecta" aceptada una vez, y fue "presionado por sus pares" para eventualmente cambiarla).
mgibsonbr
3
@Leo ¿no debería ser marcado entonces? Al buscar "script de aplazamiento html5", este es el tercer resultado en google. Esta respuesta proporciona a muchos usuarios una definición incorrecta y desactualizada. (La definición actual: "Indica que el agente de usuario puede diferir el procesamiento de la secuencia de comandos. Consulte la definición de atributo diferido en HTML 4.0").
Malavos
2
@ MarkAtRamp51 Creo que debería actualizar su respuesta. Cualquiera que encuentre esta pregunta y, por lo tanto, su respuesta no reconocerá su información histórica. Les parecerá que es la respuesta correcta hoy. Así funciona internet. Por lo tanto, debe editar su respuesta, tener en cuenta que alguna vez fue correcta y consultar la respuesta correcta.
Juuro
167

Algunos fragmentos de la especificación HTML5: http://w3c.github.io/html/semantics-scripting.html#element-attrdef-script-async

Los atributos de aplazamiento y asíncrono no deben especificarse si el atributo src no está presente.


Hay tres modos posibles que se pueden seleccionar usando estos atributos [async y diferir]. Si el atributo asíncrono está presente, el script se ejecutará de forma asíncrona tan pronto como esté disponible. Si el atributo asíncrono no está presente pero el atributo de aplazamiento está presente, entonces el script se ejecuta cuando la página ha finalizado el análisis. Si ninguno de los atributos está presente, la secuencia de comandos se obtiene y ejecuta inmediatamente, antes de que el agente de usuario continúe analizando la página.


Los detalles de procesamiento exactos para estos atributos son, por razones históricas, algo no triviales, que involucran una serie de aspectos de HTML. Por lo tanto, los requisitos de implementación están necesariamente dispersos en la especificación. Los algoritmos a continuación (en esta sección) describen el núcleo de este procesamiento, pero estos algoritmos hacen referencia y son referenciados por las reglas de análisis para las etiquetas de inicio y finalización del script en HTML, en contenido externo y en XML, las reglas para el documento. () método, manejo de scripting, etc.


Si el elemento tiene un atributo src, y el elemento tiene un atributo diferido, y el elemento ha sido marcado como "insertado por analizador", y el elemento no tiene un atributo asíncrono:

El elemento debe agregarse al final de la lista de scripts que se ejecutarán cuando el documento haya finalizado el análisis asociado con el Documento del analizador que creó el elemento.

Alohci
fuente
37
Tal vez, mi respuesta aquí evitará que la gente rechace mi respuesta, debido a su comentario no útil. La respuesta aceptada no es incorrecta, la respuesta es diferente, porque a principios de 2011 la especificación HTML5 era menos relevante para los navegadores web convencionales que lo que es actualmente. Esta respuesta podría ser mejor en el futuro, pero la respuesta aceptada no es INCORRECTA según ningún estándar.
Mark At Ramp51
3
Si bien es útil saber lo que dice la especificación, resulta que algunos navegadores como IE <9 se implementan defermal . Si lo usa defer, no puede confiar en que los archivos de script se ejecuten en orden en algunos navegadores.
Flimm
2
@Flimm No solo IE, parece que el orden de ejecución tampoco está garantizado en Firefox .
Franklin Yu
La primera cita ya no es válida, ¿verdad? Ahora puedo leer esto: "El atributo no debe especificarse si el atributo src no está presente o si el script no es un script clásico". Y un script clásico es uno sin src = "" también.
Félix Sanz
158

La verdadera respuesta es: porque no puedes confiar en diferir.

En concepto, diferir y asíncrono difieren de la siguiente manera:

async permite que el script se descargue en segundo plano sin bloquear. Luego, en el momento en que finaliza la descarga, el procesamiento se bloquea y se ejecuta ese script. El procesamiento se reanuda cuando el script se ha ejecutado.

aplazar hace lo mismo, excepto las afirmaciones para garantizar que los scripts se ejecuten en el orden en que se especificaron en la página, y que se ejecutarán una vez que el documento haya finalizado el análisis. Por lo tanto, algunas secuencias de comandos pueden finalizar la descarga y luego sentarse y esperar a que se descarguen más tarde pero aparecieron antes que ellas.

Desafortunadamente, debido a lo que realmente es una pelea de gatos estándar, la definición de diferir varía de especificación a especificación, e incluso en las especificaciones más recientes no ofrece una garantía útil. Como lo demuestran las respuestas aquí y este problema , los navegadores implementan diferir de manera diferente:

  • En ciertas situaciones, algunos navegadores tienen un error que hace que los deferscripts se salgan de orden.
  • Algunos navegadores retrasan el DOMContentLoadedevento hasta después de que los deferscripts se hayan cargado, y otros no.
  • Algunos navegadores obedecen defera <script>elementos con código en línea y sin un srcatributo, y algunos lo ignoran.

Afortunadamente, la especificación al menos especifica que las anulaciones asincrónicas difieren. Por lo tanto, puede tratar todos los scripts como asíncronos y obtener una amplia gama de compatibilidad con el navegador de esta manera:

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

El 98% de los navegadores en uso en todo el mundo y el 99% en los EE. UU. Evitarán el bloqueo con este enfoque.

(Si necesita esperar hasta que el documento haya terminado de analizar, escuche el evento del DOMContentLoadedevento o use la práctica .ready()función de jQuery . De todos modos, querrá hacer esto para recurrir con gracia a los navegadores que no se implementan deferen absoluto).

Chris Moschini
fuente
13
¡Gracias, su respuesta fue la más útil para mí!
markus
55
Creo que esto es incorrecto. El beneficio de diferir es que no se ejecuta hasta que se completa el análisis de la página. Esta página tiene un buen visual para explicar la diferencia entre asíncrono y diferir: peter.sh/experiments/…
tinkerr
1
@tinkerr En concepto, tienes razón; En la práctica esto no resulta ser cierto. Debido a que no se implementa consistentemente, la garantía de secuencia no es universal y, por lo tanto, no es una garantía. Al implementar algo que le importa la ejecución. La intención del diseño es linda, pero no particularmente útil.
Chris Moschini
Solo quería señalar que Opera ha admitido el deferatributo desde la versión 15 , que se lanzó el 2 de junio de 2013 .
1
@VikasBansal Para navegadores más antiguos que no admiten asíncrono, es decir, IE más antiguo.
Chris Moschini
13

defersolo se puede usar en la <script>etiqueta para la inclusión de script externo . Por lo tanto, se recomienda su uso en las <script>etiquetas en la <head>sección.

Rajesh Paul
fuente
8

Como el atributo diferir solo funciona con la etiqueta de scripts con src. Encontró una manera de imitar diferir para secuencias de comandos en línea. Utilice el 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>

Esto se debe a que el evento DOMContentLoaded se desencadena después de que los scripts atribuidos diferidos se cargan por completo.

Bijoy Anupam
fuente
6

El atributo de aplazamiento es solo para scripts externos (solo debe usarse si el atributo src está presente).

Soumitra
fuente
4

Eche un vistazo a este excelente artículo. Sumérjase en las aguas turbias de la carga de guiones del desarrollador de Google Jake Archibald escrito en 2013.

Citando la sección relevante de ese artículo:

Aplazar

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

La especificación dice : Descargar juntos, ejecutar en orden justo antes de DOMContentLoaded. Ignore "diferir" en los scripts sin "src".

IE <10 dice : podría ejecutar 2.js a la mitad de la ejecución de 1.js. ¿No es divertido?

Los navegadores en rojo dicen : No tengo idea de qué es esta cosa de "aplazamiento", voy a cargar los scripts como si no estuviera allí.

Otros navegadores dicen : Ok, pero no podría ignorar "aplazar" los scripts sin "src".

(Agregaré que las primeras versiones de Firefox activan DOMContentLoaded antes de que los deferscripts terminen de ejecutarse, según este comentario ).

Los navegadores modernos parecen admitir asynccorrectamente, pero debe estar bien con los scripts que se ejecutan fuera de servicio y posiblemente antes de DOMContentLoaded.

Flimm
fuente
1

Este atributo booleano está configurado para indicar a un navegador que el script debe ejecutarse después de que se haya analizado el documento. Dado que esta característica aún no ha sido implementada por todos los demás navegadores principales, los autores no deben suponer que la ejecución del script se aplazará. Nunca llame a document.write () desde un script diferido (desde Gecko 1.9.2, esto eliminará el documento). El atributo de aplazamiento no debe usarse en scripts que no tengan el atributo src. Desde Gecko 1.9.2, el atributo de aplazamiento se ignora en los scripts que no tienen el atributo src. Sin embargo, en Gecko 1.9.1, incluso los scripts en línea se difieren si se establece el atributo de aplazamiento.

diferir funciona con Chrome, Firefox, es decir,> 7 y Safari

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

s-sharma
fuente
0

El atributo de aplazamiento es un atributo booleano.

Cuando está presente, especifica que el script se ejecuta cuando la página ha terminado de analizar.

Nota: El atributo de aplazamiento es solo para scripts externos (solo debe usarse si el atributo src está presente).

Nota: Hay varias formas de ejecutar un script externo:

Si está presente la sincronización: la secuencia de comandos se ejecuta de forma asíncrona con el resto de la página (la secuencia de comandos se ejecutará mientras la página continúa el análisis) Si la sincronización no está presente y el aplazamiento está presente: la secuencia de comandos se ejecuta cuando la página ha finalizado el análisis. ni asíncrono ni aplazamiento está presente: el script se recupera y ejecuta inmediatamente, antes de que el navegador continúe analizando la página

srikanth_k
fuente