¿CSS debería siempre preceder a Javascript?

932

En innumerables lugares en línea he visto la recomendación de incluir CSS antes que JavaScript. El razonamiento es generalmente, de esta forma :

When it comes to ordering your CSS and JavaScript, you want your CSS to come first. The reason is that the rendering thread has all the style information it needs to render the page. If the JavaScript includes come first, the JavaScript engine has to parse it all before continuing on to the next set of resources. This means the rendering thread can't completely show the page, since it doesn't have all the styles it needs.

Mi prueba real revela algo bastante diferente:

Mi arnés de prueba

Utilizo el siguiente script de Ruby para generar retrasos específicos 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 servidor como cliente) y retrasos CSS arbitrarios. Por ejemplo, http://10.0.0.50:8081/test.css?delay=500me da un retraso de 500 ms al transferir el CSS.

Utilizo 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&amp;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:

CSS primero

Cuando incluyo el JavaScript primero, la página tarda 1.4 segundos en renderizarse:

JavaScript primero

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. Por lo tanto, parece que tener JavaScript incluye primero es más eficiente a medida que el hilo de JavaScript obtiene más tiempo de ejecución.

¿Me estoy perdiendo algo? ¿La recomendación de colocar CSS incluye antes de JavaScript no es correcta?

Está claro que podríamos agregar async 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 ordenar los bits esenciales de JavaScript y CSS en la cabeza.

9
  • 125
    ¿Es 1511 vs 1422 una diferencia estadísticamente significativa? Eso es el 6 por ciento. El umbral general para la diferencia de desempeño humano entre notable y promedio es de aproximadamente el 20 por ciento. Jeff Atwood 14 de febrero de 2012 a las 4:41
  • dieciséis
    el punto es que reordenar elimina este retraso arbitrario, puede configurar el retraso en lo que desee, es solo una demostración del problema. Sam Saffron 14 de febrero de 2012 a las 4:58
  • 3
    ¿Tu retraso fue de 100 ms? la diferencia en sus capturas de pantalla es de 89 ms. En su URL está delay=400&amp;jsdelay=1000y delay=500que no está ni cerca de 100 ms o 89 ms. Supongo que no tengo claro a qué números se refiere. Jeff Atwood 14 de febrero de 2012 a las 5:32
  • 4
    "Si las inclusiones de Javascript son lo primero, el motor de Javascript tiene que analizarlo todo antes de continuar con el siguiente conjunto de recursos. Esto significa que el hilo de renderizado no puede mostrar la página por completo, ya que no tiene todos los estilos que necesita. . " - si la inclusión de JS está en el encabezado, la JS se ejecutará antes de que se procese la página, independientemente de si la inclusión de CSS fue antes o después. nnnnnn 14/02/12 a las 5:37
  • 165
    No estoy seguro si ha considerado esto, pero la percepción del tiempo de carga también es importante. Entonces, por ejemplo, si cargar el CSS primero le da incluso solo el color / textura de fondo de la página, parecería ser más rápido. Los tiempos de carga absolutos pueden no ser indicativos de esto. Rakesh Pai 14 de febrero de 2012 a las 8:49
730

Esta es una pregunta muy interesante. Siempre he puesto mis CSS <link href="...">antes que mis JS <script src="...">porque "leí una vez 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:

  • Se aseguró de que no hubiera almacenamiento en caché HTTP para que el navegador tuviera que realizar una descarga completa cada vez que se carga una página.
  • Para simular la realidad, incluí jQuery y el CSS H5BP (por lo que hay una cantidad decente de script / CSS para analizar)
  • Configure dos páginas: una con CSS antes del script y otra con CSS después del script.
  • Se registró el tiempo que tardó en <head>ejecutarse el script externo en el
  • Se registró cuánto tiempo tardó en <body>ejecutarse el script en línea en el , que es análogo a DOMReady.
  • Retraso en el envío de CSS y / o script al navegador en 500 ms.
  • Ejecutó la prueba 20 veces en los 3 principales navegadores.

Resultados

Primero, con el archivo CSS retrasado 500 ms:

     Browser: Chrome 18    | IE 9         | Firefox 9
         CSS: first  last  | first  last  | first last
=======================================================
Header Exec |              |              |
Average     | 583ms  36ms  | 559ms  42ms  | 565ms 49ms
St Dev      | 15ms   12ms  | 9ms    7ms   | 13ms  6ms
------------|--------------|--------------|------------
Body Exec   |              |              |
Average     | 584ms  521ms | 559ms  513ms | 565ms 519ms
St Dev      | 15ms   9ms   | 9ms    5ms   | 13ms  7ms

A continuación, configuré jQuery para retrasar 500 ms en lugar del CSS:

     Browser: Chrome 18    | IE 9         | Firefox 9
         CSS: first  last  | first  last  | first last
=======================================================
Header Exec |              |              |
Average     | 597ms  556ms | 562ms  559ms | 564ms 564ms
St Dev      | 14ms   12ms  | 11ms   7ms   | 8ms   8ms
------------|--------------|--------------|------------
Body Exec   |              |              |
Average     | 598ms  557ms | 563ms  560ms | 564ms 565ms
St Dev      | 14ms   12ms  | 10ms   7ms   | 8ms   8ms

Por último, me puse tanto jQuery y CSS para retrasar por 500 ms:

     Browser: Chrome 18    | IE 9         | Firefox 9
         CSS: first  last  | first  last  | first last
=======================================================
Header Exec |              |              |
Average     | 620ms  560ms | 577ms  577ms | 571ms 567ms
St Dev      | 16ms   11ms  | 19ms   9ms   | 9ms   10ms
------------|--------------|--------------|------------
Body Exec   |              |              |
Average     | 623ms  561ms | 578ms  580ms | 571ms 568ms
St Dev      | 18ms   11ms  | 19ms   9ms   | 9ms   10ms

Conclusiones

Primero, es importante tener en cuenta que estoy operando bajo el supuesto de que tiene scripts ubicados en el <head>de su documento (a diferencia del final del <body>). Hay varios argumentos sobre por qué puede vincular sus scripts en el <head>versus al final del documento, pero eso está fuera del alcance de esta respuesta. Se trata estrictamente de si <script>s debe ir antes que <link>s en el <head>.

En los navegadores DESKTOP modernos, parece que vincular primero a CSS nunca proporciona una ganancia de rendimiento. Poner CSS después de la secuencia de comandos le da una cantidad trivial de ganancia cuando tanto CSS como la secuencia de comandos se retrasan, pero le brinda grandes ganancias cuando CSS se retrasa. (Mostrado por las lastcolumnas en el primer conjunto de resultados).

Dado que vincular a CSS en último lugar no parece perjudicar el rendimiento, pero puede proporcionar ganancias en determinadas circunstancias, debe vincular a hojas de estilo externas después de vincular a scripts externos solo en navegadores de escritorio si el rendimiento de los navegadores antiguos no es un problema. Siga leyendo para conocer la situación móvil.

¿Por qué?

Históricamente, cuando un navegador encontraba una <script>etiqueta que apuntaba a un recurso externo, el navegador dejaba de analizar el HTML, recuperaba el script, lo ejecutaba y luego continuaba analizando el HTML. Por el contrario, si el navegador encuentra una <link>hoja de estilo externa, continuará analizando el HTML mientras busca el archivo CSS (en paralelo).

Por lo tanto, el consejo ampliamente repetido de poner las hojas de estilo primero: se descargarían primero y el primer script que se descargaría podría cargarse en paralelo.

Sin embargo, los navegadores modernos (incluidos todos los navegadores con los 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, colocar los scripts en primer lugar afectará el rendimiento, ya que no se descargarán en paralelo.

Soporte del navegador

El análisis especulativo se implementó por primera vez en: (junto con el porcentaje de usuarios de navegadores de escritorio en todo el mundo que utilizan esta versión o una superior a enero de 2012)

  • Chrome 1 (WebKit 525) (100%)
  • IE 8 (75%)
  • Firefox 3.5 (96%)
  • Safari 4 (99%)
  • Opera 11.60 (85%)

En total, aproximadamente el 85% de los navegadores de escritorio que se utilizan 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 según la audiencia específica de su sitio. (Y recuerde 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 la heterogeneidad del navegador móvil y el panorama del sistema operativo. Dado que la representación especulativa se implementó en WebKit 525 (lanzado en marzo de 2008), y casi todos los navegadores móviles que valen la pena se basan en WebKit, podemos concluir que "la mayoría" de los navegadores móviles deberían admitirlo. Según quirksmode , iOS 2.2 / Android 1.0 usa WebKit 525. No tengo idea de cómo es Windows Phone.

Sin embargo, ejecuté la prueba en mi dispositivo Android 4 y, aunque vi números similares a los resultados del escritorio, lo conecté al fantástico nuevo depurador remoto en Chrome para Android, y la pestaña Red mostró que el navegador estaba esperando descargar CSS hasta que los JavaScripts se carguen 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 la CPU, la memoria y / o la red inherentes a los dispositivos móviles.

Código

Perdone el descuido, esto fue Q&D.

app.js

var express = require('express')
, app = express.createServer()
, fs = require('fs');

app.listen(90);

var file={};
fs.readdirSync('.').forEach(function(f) {
    console.log(f)
    file[f] = fs.readFileSync(f);
    if (f != 'jquery.js' && f != 'style.css') app.get('/' + f, function(req,res) {
        res.contentType(f);
        res.send(file[f]);
    });
});


app.get('/jquery.js', function(req,res) {
    setTimeout(function() {
        res.contentType('text/javascript');
        res.send(file['jquery.js']);
    }, 500);
});

app.get('/style.css', function(req,res) {
    setTimeout(function() {
        res.contentType('text/css');
        res.send(file['style.css']);
    }, 500);
});


var headresults={
    css: [],
    js: []
}, bodyresults={
    css: [],
    js: []
}
app.post('/result/:type/:time/:exec', function(req,res) {
    headresults[req.params.type].push(parseInt(req.params.time, 10));
    bodyresults[req.params.type].push(parseInt(req.params.exec, 10));
    res.end();
});

app.get('/result/:type', function(req,res) {
    var o = '';
    headresults[req.params.type].forEach(function(i) {
        o+='\n' + i;
    });
    o+='\n';
    bodyresults[req.params.type].forEach(function(i) {
        o+='\n' + i;
    });
    res.send(o);
});

css.html

<!DOCTYPE html>
<html>
    <head>
        <title>CSS first</title>
        <script>var start = Date.now();</script>
        <link rel="stylesheet" href="style.css">
        <script src="jquery.js"></script>
        <script src="test.js"></script>
    </head>
    <body>
        <script>document.write(jsload - start);bodyexec=Date.now()</script>
    </body>
</html>

js.html

<!DOCTYPE html>
<html>
    <head>
        <title>CSS first</title>
        <script>var start = Date.now();</script>
        <script src="jquery.js"></script>
        <script src="test.js"></script>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <script>document.write(jsload - start);bodyexec=Date.now()</script>
    </body>
</html>

test.js

var jsload = Date.now();


$(function() {
    $.post('/result' + location.pathname.replace('.html','') + '/' + (jsload - start) + '/' + (bodyexec - start));
});

jquery.js era jquery-1.7.1.min.js

9
  • 140
    esta es una respuesta fantástica, ¡gracias por usar la ciencia! Según su resultado, "en los navegadores modernos, parece que vincular primero a CSS nunca proporciona una ganancia de rendimiento" , creo que la respuesta al título de la pregunta es , el antiguo consejo de CSS primero es claramente inválido. Jeff Atwood 14 de febrero de 2012 a las 7:54
  • Con respecto a la actualización de @ josh3736 sobre lo inverso en el móvil ... este es un caso en el que no debemos adelantarnos a este cambio significativo. Tendría curiosidad por saber cómo se comportan otros navegadores móviles (webkit, gecko, presto, trident, etc.) ya que el rendimiento en dispositivos móviles suele ser más importante. scunliffe 14/02/12 a las 19:17
  • 1
    También debería intentar agregar algo de lentitud a la impresión de css / js, para simular las velocidades de un servidor lento. kirb 14/02/12 a las 21:19
  • ¿Qué tal si usa defer o async? ¿Eso cambia? (pruebe con scripts en línea y sin scripts en línea) ¿Eso cambia? brunoais 25/12/12 a las 18:28
  • 1
    "Primero, es importante tener en cuenta que estoy operando bajo el supuesto de que tiene scripts ubicados en el <head>de su documento (en contraposición al final del <body>)". Destacaría eso mucho antes en la respuesta, como en la parte superior. Incluyendo una scripten la headque 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 alguna o dos líneas extrañas del script en línea , pero eso es todo. El defecto, sin muy buenas razones contrarias, debería ser el final del cuerpo. T.J. Crowder 12/12/18 a las 11:46
311

Hay dos razones principales para poner CSS antes que JavaScript.

  1. 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.jsseguido por b.css, se descargan secuencialmente: primero a, luego b. Si ha b.cssseguido a.js, se descargan en paralelo para que la página se cargue más rápidamente.

  2. No se procesa nada hasta que se descargan todas las hojas de estilo; esto es cierto en todos los navegadores. Los scripts son diferentes: bloquean la representación de todos los elementos DOM que están debajo de la etiqueta del script en la página. Si coloca sus scripts en HEAD, significa que toda la página está bloqueada para que no se procese hasta que se descarguen todas las hojas de estilo y todos los scripts. Si bien tiene sentido bloquear todo el renderizado de las hojas de estilo (para obtener el estilo correcto la primera vez y evitar el destello del contenido sin estilo FOUC), no tiene sentido bloquear el renderizado de toda la página para los scripts. A menudo, los scripts no afectan ningún elemento DOM o solo 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 una secuencia de comandos en HEAD, por lo que toda la página está en blanco hasta que termine de descargarse. Sin embargo, si movemos el script al final del bloque BODY, el encabezado de la página se renderiza, ya que esos elementos DOM se encuentran encima de la etiqueta SCRIPT, como puede ver en esta página .

7
  • 11
    Honorable Steve me adelantó en la respuesta, pero agregaré un artículo relevante a lo que menciona: stevesouders.com/blog/2009/04/27/…Juan Pablo Buritica 14 de febrero de 2012 a las 6:31
  • 4
    vea qué navegadores admiten el asyncatributo, que Steve recomienda aquí cuando dice "aún mejor cárguelos de forma asincrónica" - stackoverflow.com/questions/1834077/…Jeff Atwood 14 de febrero de 2012 a las 6:42
  • Oye, ¿puedes decirme por qué alguien vincularía archivos CSS con @importdirectivas? Josh Stodola 14 de febrero de 2012 a las 6:42
  • 7
    ¿Cuál es el origen de 2) y, si es cierto, puede explicar por qué en ocasiones una página termina de cargar el contenido y luego se aplica el CSS uno o dos segundos después? (Esto ha sucedido, raramente, en mis propias páginas donde el CSS estaba en las etiquetas <head>)Izkata 14/02/12 a las 14:59
  • 2
    Entonces, ¿deberíamos poner jQuery+ jQuery UI+ $(document).ready(function () { });al final de la página? ¿Funcionará siempre como se esperaba? Olivier Pons 16 de febrero de 2012 a las 9:06
45

No enfatizaría demasiado en los resultados que has obtenido, creo que es subjetivo, pero tengo una razón para explicarte que es mejor poner CSS antes que js.

Durante la carga de su sitio web, hay dos escenarios que verá:

CASO 1: pantalla blanca> sitio web sin estilo> sitio web con estilo> interacción> sitio web con estilo e interactivo

CASO 2: pantalla blanca> sitio web sin estilo> interacción> sitio web con estilo> sitio web con estilo e interactivo


Honestamente, no puedo imaginar a nadie eligiendo el Caso 2. Esto significaría que los visitantes que utilicen conexiones lentas a Internet se encontrarán con un sitio web sin estilo, que les permitirá interactuar con él mediante Javascript (ya que ya está cargado). Además, la cantidad de tiempo dedicado a mirar un sitio web sin estilo se maximizaría de esta manera. ¿Por qué alguien querría eso?

También funciona mejor como dice jQuery

"When using scripts that rely on the value of CSS style properties, it's important to reference external stylesheets or embed style elements before referencing the scripts".

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 alto de un div) no se cargará correctamente. Parece que con el orden de carga incorrecto, las propiedades correctas son "a veces" conocidas por Javascript (¿quizás esto es causado por una condición de carrera?). Este efecto parece mayor o menor según el navegador utilizado.

2
  • 2
    ¿Cómo garantizaría que todo el CSS se cargue antes de que se ejecute JavaScript? ¿Puedes? o si su javascript es lo suficientemente robusto para lidiar con la situación en la que los estilos no necesariamente se cargan. Jonnio 15/02/12 a las 12:13
  • @Jonnio Si su JS tiene una dependencia, entonces debe hacer esa dependencia explícita. De lo contrario, siempre tendrá problemas de sincronización poco frecuentes. Los módulos ES6 son una buena manera de hacer que eso suceda, pero hay muchas bibliotecas que también podrían usarse. kmkemp 9/11/18 a las 19:24
28

¿Se realizaron sus pruebas en su computadora personal o en un servidor web? ¿Es una página en blanco o es un sistema en línea complejo con imágenes, bases de datos, etc.? ¿Sus scripts realizan una simple acción de evento de desplazamiento o son un componente central de cómo su sitio web se representa e interactúa con el usuario? Hay varias cosas a considerar aquí, y la relevancia de estas recomendaciones casi siempre se convierte en reglas cuando se aventura en el desarrollo web de alto calibre.

El propósito de la regla de "poner las hojas de estilo en la parte superior y los 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.

Dejando todo lo demás a un lado: asumiendo que su prueba es válida, y 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 que todo aparezca en la pantalla de un usuario) es diferente e Internet está en constante evolución.

2
  • 1
    Aprecio el punto que está haciendo en negrita, pero el OP está hablando de lo que sucede cuando varía el orden con ambos en la parte superior, ninguno en la parte inferior. nnnnnn 14 de febrero de 2012 a las 5:35
  • 1
    Por lo tanto, "asumiendo que [su] prueba es válida". skippr 14 de febrero de 2012 a las 5:40
22

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 donde CSS es realmente un elemento principal en la parte posterior), cargar el CSS después de que JS esté en ruso puede generar condiciones de carrera, donde el elemento cambia de tamaño antes que los estilos CSS se aplican y, por lo tanto, se ve extraño cuando los estilos finalmente se activan. Si cargo el CSS de antemano, puedo garantizar que las cosas se ejecuten en el orden previsto y que el diseño final es el que quiero que sea.

6
  • 2
    esto se romperá un día en algún navegador. No lo estoy adivinando. jcolebrand 15/02/12 a las 18:14
  • 1
    jcolebrand: Sí, creo que no había bebido suficiente café cuando escribí esto. (En retrospectiva, supongo que lo importante es evitar la carga dinámica de CSS y poner el JS dentro de un evento domReady si necesita hacer un dimensionamiento dinámico)hugomg 15 feb.12 a las 18:25
  • Los scripts no deberían cambiar ninguna visualización. Ese es el trabajo de CSS. HTML = contenido, CSS = cómo mostrar contenido, javascript cambia el contenido de forma dinámica. Además, js solo debería actuar después (o mientras) el DOMContentLoaded se activa con algunas situaciones pequeñas pero muy específicas. brunoais 25/12/12 a las 18:36
  • @brunoais: Sin embargo, algunos diseños solo se pueden crear con Javascript. Por ejemplo, cualquier cosa que necesite ser redimensionada dinámicamente debe hacerse a través de Javascript y algunas cosas (como tener un tamaño de 100% - 20px) necesitan que Javascript se haga de manera portátil en navegadores antiguos. hugomg 25/12/12 a las 21:04
  • @missingno En esos casos, simplemente use el evento DOMContentLoaded, de todos modos. Pero entiendo lo que quieres decir. (¡Estúpido IE!)brunoais 25/12/12 a las 21:10
11

¿La recomendación de incluir CSS antes que JavaScript no es válida?

No si lo trata como una simple recomendación. Pero si lo trata como una regla estricta y rápida, sí, no es válida.

De https://developer.mozilla.org/en-US/docs/Web/Reference/Events/DOMContentLoaded

Stylesheet loads block script execution, so if you have a <script> after a <link rel="stylesheet" ...> the page will not finish parsing - and DOMContentLoaded will not fire - until the stylesheet is loaded.

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 que se cargarán o en hojas de estilo que se aplicarán, entonces si leo la referencia anterior correctamente, ese código debe posponerse hasta el evento onload.

No creo que una talla de calcetín sirva para todos, aunque así se venden y sé que una talla de zapato no sirve para todos. No creo que haya una respuesta definitiva a la que cargar primero, estilos o guiones. Es más una decisión caso por caso de qué debe cargarse, en qué orden y qué se puede diferir hasta más tarde, ya que no se encuentra en la "ruta crítica".

Hablar con el observador que comentó que es mejor retrasar la capacidad de interacción de los usuarios hasta que la hoja sea bonita. Hay muchos de ustedes y molestan a sus contrapartes que sienten lo contrario. Llegaron a un sitio para lograr un propósito y los retrasos en su capacidad para interactuar con un sitio mientras esperan que las cosas que no importan terminen de cargarse son muy frustrantes. No estoy diciendo que estés equivocado, solo que debes ser consciente de 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 solo representaran divs 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 para desplazarme incluso por el contenido del sitio mientras se cargan los anuncios hinchados. Pero ese es solo el punto de vista de una persona.

  • Conozca a sus usuarios y lo que ellos valoran.
  • Conozca a sus usuarios y qué entorno de navegación utilizan.
  • Sepa qué hace cada archivo y cuáles son sus requisitos previos. Hacer que todo funcione tendrá prioridad sobre la velocidad y la belleza.
  • Utilice herramientas que le muestren la línea de tiempo de la red durante el desarrollo.
  • Prueba en cada uno de los entornos que utilizan tus usuarios. Puede ser necesario modificar dinámicamente (del lado del servidor, al crear la página) el orden de carga según el entorno de los usuarios.
  • En caso de duda, modifique el orden y vuelva a medir.
  • Es posible que mezclar estilos y scripts en el orden de carga sea óptimo; no todos de uno, luego todos del otro.
  • Experimente no solo en qué orden cargar los archivos, sino también en dónde. ¿Cabeza? ¿En cuerpo? ¿Después del cuerpo? DOM listo / cargado? ¿Cargado?
  • Considere las opciones asíncronas y diferidas cuando sea apropiado para reducir la demora neta que experimentará el usuario antes de poder interactuar con la página. Pruebe para determinar si ayudan o duelen.
  • Siempre habrá compensaciones a considerar al evaluar el orden de carga óptimo. Bastante vs. Responsive siendo solo uno.
2
  • 1
    El artículo vinculado ya no dice "La hoja de estilo carga la ejecución del script de bloque". ¿Eso ya no es cierto? Greg 10/08/15 a las 19:16
  • @ Greg: sigue siendo cierto. Los scripts deben poder consultar atributos DOM .style, por lo que las hojas de estilo aún bloquean la ejecución del script. Es posible que no bloqueen la carga de scripts , si son inteligentes, pero bloquearán los eventos script.onLoad. Jimmy Breck-McKye 5 de junio de 2017 a las 11:13
11

Actualizado 2017-12-16

No estaba seguro de las pruebas en OP. Decidí experimentar un poco y terminé rompiendo algunos de los mitos.

Synchronous <script src...> will block downloading of the resources below it until it is downloaded and executed

Esto ya no es cierto . Eche un vistazo a la cascada generada por Chrome 63:

<head>
<script src="//alias-0.redacted.com/payload.php?type=js&amp;delay=333&amp;rand=1"></script>
<script src="//alias-1.redacted.com/payload.php?type=js&amp;delay=333&amp;rand=2"></script>
<script src="//alias-2.redacted.com/payload.php?type=js&amp;delay=333&amp;rand=3"></script>
</head>

Inspector de red de cromo -> cascada

<link rel=stylesheet> will not block download and execution of scripts below it

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í ). Eche un vistazo al gráfico de rendimiento generado por Chrome 63:

<link href="//alias-0.redacted.com/payload.php?type=css&amp;delay=666" rel="stylesheet">
<script src="//alias-1.redacted.com/payload.php?type=js&amp;delay=333&amp;block=1000"></script>

Herramientas de desarrollo de Chrome -> rendimiento


Teniendo en cuenta lo anterior, los resultados en OP se pueden explicar de la siguiente manera:

CSS primero:

CSS Download  500ms:<------------------------------------------------>
JS Download   400ms:<-------------------------------------->
JS Execution 1000ms:                                                  <-------------------------------------------------------------------------------------------------->
DOM Ready   @1500ms:                                                                                                                                                      ◆

JS primero:

JS Download   400ms:<-------------------------------------->
CSS Download  500ms:<------------------------------------------------>
JS Execution 1000ms:                                        <-------------------------------------------------------------------------------------------------->
DOM Ready   @1400ms:                                                                                                                                            ◆
2
  • Es también por eso que document.write () es una de las peores ideas jamás hechas para HTMLDOM. brunoais 25/12/12 a las 18:38
  • 1
    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? No tiene mucho sentido para mí, el orden de JS ejecutado no dice nada sobre su propósito. Thorsten Schöning 31/12/18 a las 13:23
4

No estoy exactamente seguro de cómo su prueba 'renderiza' el tiempo que usa el script java. Sin embargo, considere esto

Una página en su sitio tiene 50k, lo cual no es descabellado. El usuario está en la costa este mientras que su servidor está en el oeste. MTU definitivamente no es 10k, por lo que habrá algunos viajes de ida y vuelta. Puede tardar 1/2 segundo en recibir su página y hojas de estilo. Normalmente (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 interrumpe en la mitad de la página, pero ignoremos eso (me sucede ocasionalmente y creo que el css se muestra, pero no estoy 100% seguro).

Dado que 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, toma el resto de la página y los archivos javascript (que son muchos más bytes), la página no tiene estilo, lo que hace que el sitio / conexión parezca lento.

INCLUSO SI el intérprete de JS se niega a comenzar hasta que el CSS esté listo, el tiempo necesario para descargar el código javascript, especialmente cuando el servidor está lejos del tiempo de CSS, lo que hará que el sitio no se vea bien.

Es una pequeña optimización, pero esa es la razón.

1
  • 1
    el servidor está en la costa este, fwiw. Aparentemente, también ignora el hecho de que ahora usan una CDN. jcolebrand 15 feb.12 a las 18:15
3

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 (a diferencia de la sabiduría tradicional de poner CSS primero) brinda un mejor rendimiento, pero no hay un razonamiento lógico dado para ello, y carece de validación con respecto a la aplicabilidad generalizada, por lo que puede ignóralo por ahora.

Entonces, para responder a la pregunta: sí. La recomendación de incluir CSS antes de JS no es válida para los navegadores modernos. Coloque CSS donde quiera y ponga JS hacia el final, como sea posible.

1
  • Un caso de uso para colocar un script javascript en la etiqueta principal e incluso antes del CSS, es lidiar con un estilo que el navegador no puede conocer de antemano, como la tendencia reciente del modo Oscuro / Claro en las aplicaciones web. Debe ser un pequeño script solo con el propósito de leer la sesión y luego configurar el estilo (ya sea variables css u otros medios) según la sesión del usuario. Esto evita un destello del estilo predeterminado de renderizado antes de que el script cambie al estilo establecido. Caleb Taylor 07/07/20 a las 15:15
1

Steve Souders ya ha dado una respuesta definitiva pero ...

Me pregunto si hay algún problema tanto con la prueba original de Sam como con la repetición de Josh.

Ambas pruebas parecen haberse realizado en conexiones de baja latencia donde configurar la conexión TCP tendrá un costo trivial.

No estoy seguro de cómo afecta esto al resultado de la prueba y me gustaría ver las cascadas de 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. (Limpiar las primeras altera esa dinámica, pero no se está haciendo aquí)

En los navegadores más nuevos, la segunda conexión TCP se abre de forma especulativa, 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 estoy seguro de cómo / si esto afecta el resultado de las pruebas.

4
  • no seguir, a menos que tenga canalización, lo cual es increíblemente raro, es muy poco probable que se reduzca la configuración de la conexión ... de acuerdo, la prueba debe repetirse en baja latenciaSam Saffron 14/03/12 a las 10:53
  • Si observa esta cascada, puede ver dónde Chrome abre especulativamente una segunda conexión antes de que sea necesaria webpagetest.org/result/… (IE9 hace lo mismo) ... Estaba pensando en una latencia normal para propósitos de TCP en lugar de baja, de qué tipo del entorno en el que se realizó la prueba? Andy Davies 14/03/12 a las 11:12
  • 2
    Re: "Steve Souders ya ha dado una respuesta definitiva pero ..." Lo que pasa con la evolución web es que no hay respuestas definitivas. :) Hay 3-4 formas de cargar scripts y las cosas cambian. El actual correcta semántica en realidad debería haber sido por Steve decir "CSS poner ante síncrono JavaScript" De lo contrario la gente se equivoca al generalizar como que sea una regla para todos los scripts ...hexalys 18/10/2013 a las 7:24
  • Sí, pero la mayoría de la gente simplemente incluye guiones sincrónicamente, por lo que el consejo de Steve es bueno para los no iniciados. Andy Davies 19/10/2013 a las 9:46
1

Creo que esto no será cierto para todos los casos. Porque css se descargará en paralelo pero js no puede. Considere para el mismo caso,

En lugar de tener un solo css, tome 2 o 3 archivos css y pruébelo de estas formas,

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.

0

Debemos tener en cuenta que los nuevos navegadores han trabajado en sus motores Javascript, sus analizadores, etc., optimizando el código común y los problemas de marcado de manera que los problemas experimentados en navegadores antiguos como <= IE8 ya no sean relevantes, no solo con en lo que respecta al marcado, pero también al uso de variables 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.

1
  • El rendimiento siempre es un problema. Casi ignoro que existen navegadores que no siguen las especificaciones. Solo preparo mi código de tal manera que los que siguen las especificaciones funcionen a toda velocidad y los demás lo hago de manera que funcione. Entonces, por ejemplo, si solo funciona en IE8, todo está bien. brunoais 25/12/12 a las 18:41
0

La respuesta de 2020: probablemente no importe

La mejor respuesta aquí fue de 2012, así que decidí probar por mí mismo. En Chrome para Android, los recursos JS y CSS se descargan en paralelo y no pude detectar una diferencia en la velocidad de representación de la página.

Incluí un artículo más detallado en mi blog.

-5

Personalmente, no pondría demasiado énfasis en esa "sabiduría popular". Lo que pudo haber sido cierto en el pasado bien podría no serlo ahora. Asumiría que todas las operaciones relacionadas con la interpretación y la representación de una página web son completamente asincrónicas ("buscar" algo y "actuar sobre ello" son dos cosas completamente diferentes que podrían estar siendo manejadas por diferentes subprocesos, etc. ), y en cualquier caso, totalmente fuera de su control o de su preocupación.

Pondría referencias CSS en la parte "encabezado" del documento, junto con cualquier referencia a scripts externos. (Algunos guiones pueden exigir que se coloquen en el cuerpo y, de ser así, obligarlos).

Más allá de eso ... si observa que "esto parece ser más rápido / más lento que eso, en este / aquel 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 en cuántos minutos pasarán antes de que el equipo de Firefox salga con otro lanzamiento provisional de su producto? Sí, yo tampoco).