En innumerables lugares en línea, he visto la recomendación de incluir CSS antes de JavaScript. El razonamiento es generalmente de esta forma :
Cuando se trata de ordenar su CSS y JavaScript, desea que su CSS sea lo primero. La razón es que el hilo de renderizado tiene toda la información de estilo que necesita para renderizar la página. Si el JavaScript incluye primero, el motor de JavaScript debe analizarlo todo antes de continuar con el siguiente conjunto de recursos. Esto significa que el hilo de renderizado no puede mostrar completamente la página, ya que no tiene todos los estilos que necesita.
Mi prueba real revela algo bastante diferente:
Mi arnés de prueba
Utilizo el siguiente script de Ruby para generar demoras específicas para varios recursos:
require 'rubygems'
require 'eventmachine'
require 'evma_httpserver'
require 'date'
class Handler < EventMachine::Connection
include EventMachine::HttpServer
def process_http_request
resp = EventMachine::DelegatedHttpResponse.new( self )
return unless @http_query_string
path = @http_path_info
array = @http_query_string.split("&").map{|s| s.split("=")}.flatten
parsed = Hash[*array]
delay = parsed["delay"].to_i / 1000.0
jsdelay = parsed["jsdelay"].to_i
delay = 5 if (delay > 5)
jsdelay = 5000 if (jsdelay > 5000)
delay = 0 if (delay < 0)
jsdelay = 0 if (jsdelay < 0)
# Block which fulfills the request
operation = proc do
sleep delay
if path.match(/.js$/)
resp.status = 200
resp.headers["Content-Type"] = "text/javascript"
resp.content = "(function(){
var start = new Date();
while(new Date() - start < #{jsdelay}){}
})();"
end
if path.match(/.css$/)
resp.status = 200
resp.headers["Content-Type"] = "text/css"
resp.content = "body {font-size: 50px;}"
end
end
# Callback block to execute once the request is fulfilled
callback = proc do |res|
resp.send_response
end
# Let the thread pool (20 Ruby threads) handle request
EM.defer(operation, callback)
end
end
EventMachine::run {
EventMachine::start_server("0.0.0.0", 8081, Handler)
puts "Listening..."
}
El mini servidor anterior me permite establecer retrasos arbitrarios para archivos JavaScript (tanto del servidor como del cliente) y retrasos arbitrarios de CSS. Por ejemplo,http://10.0.0.50:8081/test.css?delay=500
me da un retraso de 500 ms para transferir el CSS.
Yo uso la siguiente página para probar.
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<script type='text/javascript'>
var startTime = new Date();
</script>
<link href="http://10.0.0.50:8081/test.css?delay=500" type="text/css" rel="stylesheet">
<script type="text/javascript" src="http://10.0.0.50:8081/test2.js?delay=400&jsdelay=1000"></script>
</head>
<body>
<p>
Elapsed time is:
<script type='text/javascript'>
document.write(new Date() - startTime);
</script>
</p>
</body>
</html>
Cuando incluyo el CSS primero, la página tarda 1,5 segundos en renderizarse:
Cuando incluyo el JavaScript primero, la página tarda 1,4 segundos en renderizarse:
Obtengo resultados similares en Chrome, Firefox e Internet Explorer. En Opera, sin embargo, el orden simplemente no importa.
Lo que parece estar sucediendo es que el intérprete de JavaScript se niega a comenzar hasta que se descargue todo el CSS. Entonces, parece que tener JavaScript incluido primero es más eficiente ya que el hilo de JavaScript obtiene más tiempo de ejecución.
Me falta algo, ¿la recomendación de colocar CSS incluye antes de JavaScript no es correcta?
Está claro que podríamos agregar asíncrono o usar setTimeout para liberar el hilo de renderizado o poner el código JavaScript en el pie de página, o usar un cargador de JavaScript. El punto aquí es sobre el pedido de bits esenciales de JavaScript y bits CSS en la cabeza.
fuente
delay=400&jsdelay=1000
ydelay=500
que no está cerca de 100 ms o 89 ms. Supongo que no tengo claro a qué números te refieres.Respuestas:
Esta es una pregunta muy interesante. Siempre he puesto mis CSS
<link href="...">
s antes de mi JS<script src="...">
porque "una vez leí que es mejor". Entonces tienes razón; ¡Ya es hora de que hagamos una investigación real!Configuré mi propio arnés de prueba en Node (código a continuación). Básicamente, yo:
<head>
ejecutarse el<body>
ejecutarse el script en línea en , que es análogo aDOMReady
.Resultados
Primero, con el archivo CSS retrasado 500ms:
A continuación, configuro jQuery para retrasar 500 ms en lugar del CSS:
Por último, me puse tanto jQuery y CSS para retrasar por 500 ms:
Conclusiones
Primero, es importante tener en cuenta que estoy operando bajo el supuesto de que tiene scripts ubicados en el
<head>
documento (en lugar de al final del<body>
). Existen varios argumentos con respecto a por qué puede vincular sus scripts en el<head>
frente al final del documento, pero eso está fuera del alcance de esta respuesta. Esto es estrictamente acerca de si<script>
s debe ir antes de<link>
s en el<head>
.En los navegadores modernos de DESKTOP, parece que vincularse a CSS nunca proporciona una ganancia de rendimiento. Poner CSS después de la secuencia de comandos le brinda una ganancia trivial cuando se retrasan tanto la CSS como la secuencia de comandos, pero le brinda grandes ganancias cuando se retrasa la CSS. (Mostrado por las
last
columnas en el primer conjunto de resultados).Dado que vincular a CSS por última vez no parece afectar el rendimiento, pero puede proporcionar ganancias en ciertas circunstancias, debe vincular a hojas de estilo externas después de vincular a secuencias de comandos externas solo en navegadores de escritorio si el rendimiento de los navegadores antiguos no es una preocupación. Siga leyendo para conocer la situación móvil.
¿Por qué?
Históricamente, cuando un navegador encuentra una
<script>
etiqueta que apunta a un recurso externo, el navegador deja de analizar el HTML, recupera el script, lo ejecuta y luego continúa analizando el HTML. Por el contrario, si el navegador encuentra una<link>
hoja de estilo externa, continuará analizando el HTML mientras recupera el archivo CSS (en paralelo).Por lo tanto, el consejo ampliamente repetido de poner primero las hojas de estilo: se descargarían primero, y el primer script para descargar podría cargarse en paralelo.
Sin embargo, los navegadores modernos (incluidos todos los navegadores que probé anteriormente) han implementado el análisis especulativo , donde el navegador "mira hacia adelante" en el HTML y comienza a descargar recursos antes de que se descarguen y ejecuten los scripts.
En navegadores antiguos sin análisis especulativo, poner los scripts primero afectará el rendimiento ya que no se descargarán en paralelo.
Soporte de navegador
El análisis especulativo se implementó por primera vez en: (junto con el porcentaje de usuarios de navegadores de escritorio de todo el mundo que utilizan esta versión o superior a partir de enero de 2012)
En total, aproximadamente el 85% de los navegadores de escritorio en uso actualmente admiten la carga especulativa. Poner scripts antes de CSS tendrá una penalización de rendimiento en el 15% de los usuarios a nivel mundial ; YMMV basado en la audiencia específica de su sitio. (Y recuerda que ese número se está reduciendo).
En los navegadores móviles, es un poco más difícil obtener números definitivos simplemente debido a lo heterogéneo que es el navegador móvil y el panorama del sistema operativo. Dado que el renderizado especulativo se implementó en WebKit 525 (lanzado en marzo de 2008), y casi todos los navegadores móviles valiosos se basan en WebKit, podemos concluir que "la mayoría" de los navegadores móviles deberían admitirlo. De acuerdo con el modo peculiar , iOS 2.2 / Android 1.0 usa WebKit 525. No tengo idea de cómo se ve Windows Phone.
Sin embargo, ejecuté la prueba en mi dispositivo Android 4 y, aunque vi números similares a los resultados de escritorio, lo conecté al nuevo depurador remoto fantástico en Chrome para Android, y la pestaña Red mostró que el navegador realmente estaba esperando descargar CSS hasta que los JavaScripts se hayan cargado por completo; en otras palabras, incluso la versión más reciente de WebKit para Android no parece admitir el análisis especulativo. Sospecho que podría estar apagado debido a las limitaciones de CPU, memoria y / o red inherentes a los dispositivos móviles.
Código
Perdona el descuido - esto fue Q&D.
app.js
css.html
js.html
test.js
jquery.js era jquery-1.7.1.min.js
fuente
<head>
documento (en lugar de al final del<body>
)". Lo destacaría mucho antes en la respuesta, como en la parte superior. Incluyendo unascript
en lahead
que hace referencia a un archivo externo casi nunca es correcto, desde casi cualquier punto de vista (ciertamente no es el rendimiento). No recuerdo haber tenido que hacerlo en la vida real. Tal vez la línea o dos impares del script en línea , pero eso es todo. El valor predeterminado, sin muy buenas razones contrarias, debería ser el final del cuerpo.Hay dos razones principales para poner CSS antes que JavaScript.
Los navegadores antiguos (Internet Explorer 6-7, Firefox 2, etc.) bloquearían todas las descargas posteriores cuando comenzaran a descargar un script. Entonces, si ha
a.js
seguidob.css
, se descargan secuencialmente: primero a y luego b. Si hab.css
seguidoa.js
, se descargan en paralelo para que la página se cargue más rápidamente.No se procesa nada hasta que se descargan todas las hojas de estilo, esto es cierto en todos los navegadores. Las secuencias de comandos son diferentes: bloquean la representación de todos los elementos DOM que están debajo de la etiqueta de secuencia de comandos en la página. Si coloca sus scripts en HEAD, significa que se bloquea la representación de toda la página hasta que se descarguen todas las hojas de estilo y todos los scripts. Si bien tiene sentido bloquear todo el procesamiento de las hojas de estilo (para que obtenga el estilo correcto la primera vez y evite el destello de contenido sin estilo FOUC), no tiene sentido bloquear el procesamiento de toda la página para los scripts. A menudo, los scripts no afectan a ningún elemento DOM o solo a una parte de los elementos DOM. Es mejor cargar los scripts lo más bajo posible en la página, o incluso mejor cargarlos de forma asincrónica.
Es divertido crear ejemplos con Cuzillion . Por ejemplo, esta página tiene un script en el HEAD, por lo que toda la página está en blanco hasta que finalice la descarga. Sin embargo, si movemos el script al final del bloque BODY, el encabezado de la página se procesa, ya que esos elementos DOM aparecen sobre la etiqueta SCRIPT, como puede ver en esta página .
fuente
async
atributo, que Steve recomienda aquí cuando dice "aún mejor cárguelos de forma asincrónica" - stackoverflow.com/questions/1834077/…@import
directivas?jQuery
+jQuery UI
+$(document).ready(function () { });
al final de la página? ¿Funcionará siempre como se esperaba?No enfatizaría demasiado los resultados que obtuviste, creo que es subjetivo, pero tengo una razón para explicarte que es mejor poner CSS antes de js.
Durante la carga de su sitio web, hay dos escenarios que vería:
CASO 1: pantalla en blanco> sitio web sin estilo> sitio web con estilo> interacción> sitio web con estilo e interactivo
CASO 2: pantalla en blanco> sitio web sin estilo> interacción> sitio web con estilo> sitio web con estilo e interactivo
Sinceramente, no puedo imaginar que alguien elija el Caso 2. Esto significaría que los visitantes que usan conexiones lentas a Internet se enfrentarán a un sitio web sin estilo, que les permite interactuar con él usando Javascript (ya que ya está cargado). Además, la cantidad de tiempo que pasa mirando un sitio web sin estilo se maximizaría de esta manera. ¿Por qué alguien querría eso?
También funciona mejor como estados jQuery
Cuando los archivos se cargan en el orden incorrecto (primero JS, luego CSS), cualquier código Javascript que dependa de las propiedades establecidas en los archivos CSS (por ejemplo, el ancho o la altura de un div) no se cargará correctamente. Parece que con el orden de carga incorrecto, las propiedades correctas son "a veces" conocidas por Javascript (¿tal vez esto es causado por una condición de carrera?). Este efecto parece mayor o menor dependiendo del navegador utilizado.
fuente
¿Se realizaron sus pruebas en su computadora personal o en un servidor web? ¿Es una página en blanco, o es un sistema complejo en línea con imágenes, bases de datos, etc.? ¿Sus scripts realizan una acción simple de evento de desplazamiento o son un componente central de cómo su sitio web representa e interactúa con el usuario? Aquí hay varias cosas a considerar, y la relevancia de estas recomendaciones casi siempre se convierten en reglas cuando te aventuras en el desarrollo web de alto calibre.
El propósito de la regla "poner hojas de estilo en la parte superior y scripts en la parte inferior" es que, en general, es la mejor manera de lograr una representación progresiva óptima , que es fundamental para la experiencia del usuario.
Todo lo demás a un lado: suponiendo que su prueba sea válida y que realmente esté produciendo resultados contrarios a las reglas populares, no sería una sorpresa, de verdad. Cada sitio web (y todo lo que se necesita para hacer que todo aparezca en la pantalla de un usuario) es diferente e Internet está en constante evolución.
fuente
Incluyo archivos CSS antes de Javascript por una razón diferente.
Si mi Javascript necesita hacer un tamaño dinámico de algún elemento de la página (para aquellos casos de esquina en los que CSS es realmente un elemento principal en la parte posterior), cargar el CSS después de que el JS se rige puede conducir a condiciones de carrera, donde el elemento se redimensiona antes que los estilos CSS se aplican y, por lo tanto, se ven extraños cuando los estilos finalmente entran en acción. Si cargo el CSS de antemano, puedo garantizar que las cosas se ejecuten en el orden previsto y que el diseño final sea lo que quiero que sea.
fuente
¿La recomendación de incluir CSS antes de JavaScript no es válida?
No si lo tratas como una simple recomendación. Pero si lo trata como una regla dura y rápida ?, sí, no es válido.
Desde https://developer.mozilla.org/en-US/docs/Web/Reference/Events/DOMContentLoaded
Parece que necesita saber en qué se basa cada script y asegurarse de que la ejecución del script se retrase hasta después del evento de finalización correcto. Si el script se basa solo en el DOM, puede reanudarse en ondomready / domcontentloaded, si se basa en imágenes para cargar o en hojas de estilo para aplicar, entonces si leo la referencia anterior correctamente, ese código debe diferirse hasta el evento de carga.
No creo que un tamaño de calcetín se ajuste a todos, aunque esa es la forma en que se venden y sé que un tamaño de zapato no sirve para todos. No creo que haya una respuesta definitiva para cargar primero, estilos o guiones. Es más una decisión caso por caso de qué se debe cargar en qué orden y qué se puede diferir hasta más tarde como no estar en la "ruta crítica".
Para hablar con el observador que comentó que es mejor retrasar la capacidad de los usuarios para interactuar hasta que la hoja sea bonita. Hay muchos de ustedes por ahí y molestan a sus contrapartes que sienten lo contrario. Llegaron a un sitio para cumplir un propósito y los retrasos en su capacidad de interactuar con un sitio mientras esperan que las cosas que no importan terminen de cargarse son muy frustrantes. No digo que estés equivocado, solo que debes saber que existe otra facción que no comparte tu prioridad.
Esta pregunta se aplica particularmente a todos los anuncios que se colocan en sitios web. Me encantaría que los autores del sitio mostraran solo divisiones de marcador de posición para el contenido del anuncio y se aseguraran de que su sitio estuviera cargado e interactivo antes de inyectar los anuncios en un evento de carga. Incluso entonces, me gustaría ver los anuncios cargados en serie en lugar de todos a la vez porque afectan mi capacidad de desplazarme incluso por el contenido del sitio mientras se cargan los anuncios hinchados. Pero ese es solo el punto de vista de una persona.
fuente
Actualizado el 16/12/2017
No estaba seguro acerca de las pruebas en OP. Decidí experimentar un poco y terminé rompiendo algunos de los mitos.
Esto ya no es verdad . Echa un vistazo a la cascada generada por Chrome 63:
Esto es incorrecto . La hoja de estilo no bloqueará la descarga, pero que va a bloquear la ejecución del script ( pequeña explicación aquí ). Echa un vistazo al gráfico de rendimiento generado por Chrome 63:
Teniendo en cuenta lo anterior, los resultados en OP se pueden explicar de la siguiente manera:
CSS primero:
JS Primero:
fuente
The reason is that the script may want to get coordinates and other style-dependent properties of elements, like in the example above. Naturally, it has to wait for styles to load.
javascript.info/… ¿Por qué no se aplica la misma suposición en el caso de JS primero? Para mí no tiene mucho sentido, el orden de ejecución de JS no dice nada sobre su propósito.No estoy exactamente seguro de cómo está probando el tiempo de 'render' mientras usa el script java. Sin embargo considere esto
Una página en su sitio es 50k, lo cual no es irrazonable. El usuario está en la costa este mientras su servidor está en el oeste. MTU definitivamente no es 10k, por lo que habrá algunos viajes de ida y vuelta. Puede tomar 1/2 segundo para recibir su página y hojas de estilo. Por lo general, (para mí) javascript (a través del complemento jquery y demás) son mucho más que CSS. También hay lo que sucede cuando su conexión a Internet se atora en la mitad de la página, pero ignoremos eso (me sucede ocasionalmente y creo que el CSS se procesa, pero no estoy 100% seguro).
Como css está en la cabeza, puede haber conexiones adicionales para obtenerlo, lo que significa que potencialmente puede terminar antes de que lo haga la página. De todos modos, durante el tipo que toma el resto de la página y los archivos javascript (que son muchos más bytes), la página no está diseñada, lo que hace que el sitio / conexión parezca lento.
INCLUSO SI el intérprete JS se niega a comenzar hasta que el CSS haya terminado, el tiempo necesario para descargar el código javascript, especialmente cuando el servidor está lejos del tiempo CSS, lo que hará que el sitio no se vea bonito.
Es una pequeña optimización, pero esa es la razón.
fuente
Aquí hay un RESUMEN de todas las respuestas principales anteriores (o tal vez a continuación más adelante :)
Para los navegadores modernos, coloque css donde quiera. Analizarían su archivo html (al que llaman análisis especulativo ) y comenzarían a descargar css en paralelo con el análisis html.
Para los navegadores antiguos, siga colocando CSS en la parte superior (si no desea mostrar primero una página desnuda pero interactiva).
Para todos los navegadores, coloque javascript lo más abajo posible en la página, ya que detendrá el análisis de su html. Preferiblemente, descárguelo de forma asincrónica (es decir, llamada ajax)
También hay algunos resultados experimentales para un caso particular que afirma que poner javascript primero (en oposición a la sabiduría tradicional de poner CSS primero) brinda un mejor rendimiento, pero no hay un razonamiento lógico dado y carece de validación con respecto a la aplicabilidad generalizada, por lo que puede ignóralo por ahora.
Entonces, para responder la pregunta: Sí. La recomendación de incluir el CSS antes de JS no es válida para los navegadores modernos. Coloque CSS donde desee y coloque JS hacia el final, como sea posible.
fuente
Steve Souders ya ha dado una respuesta definitiva pero ...
Me pregunto si hay un problema tanto con la prueba original de Sam como con la repetición de Josh.
Parece que ambas pruebas se realizaron en conexiones de baja latencia donde la configuración de la conexión TCP tendrá un costo trivial.
No estoy seguro de cómo esto afecta el resultado de la prueba, y me gustaría mirar las cascadas para las pruebas a través de una conexión de latencia 'normal' pero ...
El primer archivo descargado debería obtener la conexión utilizada para la página html, y el segundo archivo descargado obtendrá la nueva conexión. (Vaciar los primeros altera esa dinámica, pero no se está haciendo aquí)
En los navegadores más nuevos, la segunda conexión TCP se abre especulativamente, por lo que la sobrecarga de la conexión se reduce / desaparece, en los navegadores más antiguos esto no es cierto y la segunda conexión tendrá la sobrecarga de abrirse.
No sé con certeza cómo / si esto afecta el resultado de las pruebas.
fuente
Creo que esto no será cierto para todos los casos. Porque css descargará paralelo pero js no puede. Considere para el mismo caso,
En lugar de tener un solo CSS, toma 2 o 3 archivos CSS y pruébalo de esta manera,
1) css..css..js 2) css..js..css 3) js..css..css
Estoy seguro de que css..css..js dará mejores resultados que todos los demás.
fuente
Tenemos que tener en cuenta que los nuevos navegadores han funcionado en sus motores Javascript, sus analizadores, etc., optimizando el código común y los problemas de marcado de una manera que los problemas experimentados en los navegadores antiguos como <= IE8 ya no son relevantes, no solo con en lo que respecta al marcado, pero también al uso de variables de JavaScript, selectores de elementos, etc. Puedo ver en un futuro no muy lejano una situación en la que la tecnología ha llegado a un punto en el que el rendimiento ya no es un problema.
fuente
Personalmente, no pondría demasiado énfasis en tal "sabiduría popular". Lo que pudo haber sido cierto en el pasado bien podría no serlo ahora. Supongo que todas las operaciones relacionadas con la interpretación y la representación de una página web son completamente asíncronas ("buscar" algo y "actuar sobre él" son dos cosas completamente diferentes que podrían ser manejadas por diferentes hilos, etc. ), y en cualquier caso, totalmente fuera de su control o preocupación.
Pondría referencias CSS en la parte "principal" del documento, junto con cualquier referencia a secuencias de comandos externas. (Algunas secuencias de comandos pueden exigir que se coloquen en el cuerpo y, de ser así, obligarlas)
Más allá de eso ... si observa que "esto parece ser más rápido / lento que eso, en este / ese navegador", trate esta observación como una curiosidad interesante pero irrelevante y no deje que influya en sus decisiones de diseño. Demasiadas cosas cambian demasiado rápido. (¿Alguien quiere apostar cuántos minutos pasarán antes de que el equipo de Firefox salga con otro lanzamiento provisional de su producto? Sí, yo tampoco).
fuente