renderizado - Mejora de los tiempos de carga de Javascript: concatenación frente a muchos+caché
quitar el javascript que bloquea la visualización de contenido html (7)
Me pregunto cuál de las siguientes opciones dará como resultado un mejor rendimiento para una página que carga una gran cantidad de javascript (jQuery + jQuery UI + varios otros archivos javascript). He pasado por la mayoría de las cosas de YSlow y Google Page Speed, pero me pregunto por un detalle en particular.
Una cosa clave para mí aquí es que el sitio en el que estoy trabajando no está en la red pública; es una plataforma de negocio a negocio donde casi todos los usuarios son visitantes frecuentes (y, por lo tanto, con cachés de datos, algo que YSlow supone que no será el caso para una gran cantidad de visitantes).
En primer lugar, el enfoque estándar recomendado por herramientas como YSlow es concatenar, comprimir y servir en un solo archivo cargado al final de la página. Este enfoque suena razonablemente efectivo, pero creo que una parte clave del razonamiento aquí es mejorar el rendimiento de los usuarios sin datos almacenados en caché.
El sistema que tengo actualmente es algo como esto
- Todos los archivos javascript están comprimidos y cargados en la parte inferior de la página
- Todos los archivos javascript tienen fechas de caducidad futuras, por lo que permanecerán (para la mayoría de los usuarios) en la memoria caché durante mucho tiempo.
- Las páginas solo cargan los archivos javascript que requieren, en lugar de cargar un archivo monolítico, la mayoría de los cuales no serán necesarios
Ahora, según tengo entendido, si no se ha alcanzado la fecha de caducidad de la memoria caché para un archivo javascript, la versión en caché se usa de inmediato; no hay ninguna solicitud HTTP enviada al servidor en absoluto. Si esto es correcto, supondría que tener varias etiquetas no está causando ninguna penalización de rendimiento, ya que todavía no tengo ninguna solicitud adicional en la mayoría de las páginas (recordando desde arriba que casi todos los usuarios han rellenado los cachés).
Además de esto, no cargar el JS significa que el navegador no tiene que interpretar o ejecutar todo este código adicional que no va a necesitar; como una aplicación B2B, la mayoría de nuestros usuarios lamentablemente están atrapados con IE6 y su motor JS extremadamente lento.
Otro beneficio es que, cuando el código cambia, solo es necesario recuperar de nuevo los archivos afectados, en lugar de todo el conjunto (concedido, solo se necesitaría recuperar una vez, por lo que no es tan beneficioso).
También estoy considerando usar LabJS para permitir la carga paralela de JS cuando no está en caché.
Preguntás especificas
- Si hay muchas etiquetas, pero todos los archivos se están cargando desde la memoria caché local, y se está cargando menos javascript en general, será más rápido que una etiqueta que también se está cargando desde la memoria caché, pero contiene todo el javascript necesario en cualquier lugar en el sitio, en lugar de un subconjunto apropiado?
- ¿Hay otras razones para preferir una sobre la otra?
- ¿Se aplica un pensamiento similar a CSS? (Actualmente estoy usando un enfoque mucho más monolítico para CSS)
¿Has probado el cierre de Google? Por lo que he leído al respecto, parece bastante prometedor.
http://googlecode.blogspot.com/2009/11/introducing-closure-tools.html - publicación de blog
http://axod.blogspot.com/2010/01/google-closure-compiler-advanced-mode.html - rendimiento de GC
http://www.sitepoint.com/google-closure-how-not-to-write-javascript/ - algunos consejos para javascript
A pesar de que se trata de visitas repetidas, hay muchas razones por las cuales se pudo haber borrado su caché, incluidas las herramientas de privacidad y rendimiento que eliminan los archivos de caché temporales para "acelerar su computadora".
Fusionar y minimizar las secuencias de comandos no tiene por qué ser un proceso oneroso. Escribo mi JavaScript en archivos separados, bien espaciados para que sean legibles para que sea más fácil de mantener. Sin embargo, lo sirvo a través de una página de secuencia de comandos que combina todas las secuencias de comandos en una sola secuencia de comandos y minimiza todo, por lo que una secuencia de comandos se envía al navegador con todas mis secuencias de comandos. Este es el mejor de los dos mundos mientras trabajo en una colección de archivos JavaScript que todos se pueden leer, y el visitante obtiene un archivo JavaScript comprimido, que es la recomendación para reducir las solicitudes HTTP (y, por lo tanto, el tiempo de espera).
Definitivamente me gustaría ir con el enfoque no monolítico. No solo en su caso, sino que en general le brinda más flexibilidad cuando necesita cambiar o reconfigurar algo.
Si realiza un cambio en uno de estos archivos, tendrá que fusionar, comprimir y entregar. Si está haciendo esto de forma automática, entonces está bien.
En cuanto a la pregunta del navegador "si no se ha alcanzado la fecha de caducidad de la memoria caché para un archivo javascript, entonces la versión en caché se usa de inmediato; no hay ninguna solicitud HTTP enviada al servidor", creo que hay una HTTP Solicitud realizada pero con la respuesta "NO MODIFICADO". Para asegurarse de que debe verificar todas las solicitudes realizadas al servidor web (utilizando una de las herramientas disponibles). Después de dar la respuesta, el navegador usa el recurso no modificado, el archivo js o la imagen u otro.
Buena suerte con tu B2B.
En general, es mejor tener menos solicitudes más grandes que tener muchas solicitudes pequeñas, ya que el navegador solo realizará dos (?) Solicitudes en paralelo a un dominio en particular.
Entonces, mientras dice que la mayoría de los usuarios son visitantes frecuentes, cuando la memoria caché caduque, habrá muchos viajes de ida y vuelta para los muchos archivos, en lugar de uno para un archivo monolítico.
Si lleva esto a un extremo y potencialmente tiene miles de archivos con funciones individuales en ellos, sería obvio que esto llevaría a un gran número de solicitudes cuando la memoria caché caduque.
Otra razón para tener un archivo monolítico es cuando varias partes del sitio tienen diferentes fragmentos de javascript asociados, ya que nuevamente obtiene esto en el caché cuando ingresa a la primera página, guardando las solicitudes posteriores y los viajes de ida y vuelta.
Si está preocupado por el éxito inicial al cargar un archivo javascript "grande", puede intentar cargarlo de forma asíncrona, utilizando el método descrito aquí: http://www.webmaster-source.com/2010/06/07/loading-javascript-asynchronously/
Sea cual sea el camino al final, recuerde que, dado que está configurando una fecha de modificación futura, tendrá que cambiar el nombre de los archivos javascript (y CSS) cuando se realicen cambios , de lo contrario los clientes no lo harán. recoge los cambios hasta que su caché caduque de todos modos.
PD: perfílelo en los diferentes navegadores con los diferentes métodos y escríbalo, ya que será útil para aquellos que también están atrapados en motores JS lentos como IE6 :)
He usado lo siguiente tanto para CSS como para Javascript: la mayoría de mis páginas en el informe de velocidad de Google son 94-96 / 100 y se cargan muy rápido (siempre dentro de un segundo, incluso si hay 100kb de Javascript).
1. Tengo una función de PHP para llamar a archivos: esta es una clase y almacena todos los archivos únicos que se solicitan. Mi llamada se ve algo así como:
javascript( ''jquery'', ''jquery.ui'', ''home-page'' );
2. Escupí una versión codificada en url de estas cadenas combinadas para llamar a una página dinámica de PHP:
<script type="text/javascript" src="/js/?files=eNptkFsSgjAMRffCP4zlTVmDi4iQkVwibbEUHzju3UYEHMffc5r05gJnEX8IvisHnnHPQN9cMHZeKThzJOVeex7R3AmEDhQLCEZBLHLMLVhgpaXUikRMXCJbhdTjgNcG59UJyWSVPSh_0lqSSp0KN6XNEZSYwAqt_KoBY-lRRvNblBZrYeHQYdAOpHPS-VeoTpteVFwnNGSLX6ss3uwe1fi-mopg8aqt7P0LzIWwz-T_UCycC2sQavrp-QIsrnKh"></script>
3. Esa página PHP dinámica toma decodifica la cadena y crea una matriz de los archivos a los que se necesita llamar. Se crea una ruta de archivo de caché:
$compressed_js_file_path = $_SERVER[''DOCUMENT_ROOT''] . ''/cache/js/'' . md5( implode( ''|'', $js_files ) ) . ''.js'';
4. Comprueba si esa ruta de acceso del archivo ya existe en el caché, si es así, simplemente lee el archivo:
if( file_exists( $compressed_js_file_path ) ) {
echo file_get_contents( $compressed_js_file_path );
} else {
5. Si no existe, comprime todo el javascript en un archivo "monolito", pero se da cuenta de que SOLO tiene el javascript necesario para esa página, no para todo el sitio.
if( $fh = @fopen( $compressed_js_file_path, ''w'' ) ) {
fwrite( $fh, $js );
fclose( $fh );
}
// Echo the compressed Javascript
echo $js;
Te he dado extractos del código. El programa que utilices para comprimir javascript depende completamente de ti. Lo uso tanto con CSS como con Javascript para que todos esos archivos requieran 1 solicitud HTTP, el resultado se almacena en caché en el servidor (simplemente elimine ese archivo si cambia algo), y solo tiene el Javascript y CSS necesarios para esa página .
Realmente creo que necesitas hacer algunas mediciones para descubrir si una solución es mejor que la otra. Puede usar JavaScript y los datos de registro para tener una idea clara de lo que sus usuarios están viendo.
Primero, analice sus registros para ver si su tasa de caché es realmente tan buena como lo esperaría para su base de usuarios. Por ejemplo, si cada página html incluye jquery.js, revise los registros durante un día. ¿Cuántas solicitudes había para las páginas html? ¿Cuántos para jquery.js? Si la tasa de caché es buena, debería ver muchas menos solicitudes para jquery.js que para las páginas html. Probablemente quiera hacer esto por un día justo después de una actualización, y también un día unas semanas después de una actualización, para ver cómo afecta eso a la tasa de caché.
A continuación, agregue algunas medidas simples a su página en JavaScript. ¿Dijiste que las etiquetas de script están en la parte inferior, así que asumo que se ve así?
<html>
<!-- all your HTML content... -->
<script src="jquery.js"></script>
<script src="jquery-ui.js"></script>
<script src="mycode.js"></script>
En ese caso, usted calcula cuánto tiempo demora la carga de JS y hace ping al servidor de esta manera:
<html>
<!-- all your HTML content... -->
<script>var startTime = new Date().getTime();</script>
<script src="jquery.js"></script>
<script src="jquery-ui.js"></script>
<script src="mycode.js"></script>
<script>
var endTime = new Date().getTime();
var totalTime = endTime - startTime; // In milliseconds
new Image().src = "/time_tracker?script_load=" + totalTime;
</script>
Luego, puede mirar en los registros de / time_tracker (o como quiera que lo llame) y ver cuánto tiempo le lleva a la gente cargar los scripts.
Si su tasa de caché no es buena y / o no está satisfecho con el tiempo que tarda en cargar los scripts, intente mover todos los scripts a un archivo concatenado / minificado en una de sus páginas, y mida cuánto tiempo lleva para cargar de la misma manera. Si los resultados parecen prometedores, haz el resto del sitio.
Yo diría que lo más importante es centrarse en la percepción de la velocidad .
Lo primero que hay que tener en cuenta es que no existe una fórmula de ganar-ganar , sino un umbral en el que un archivo javascript crece hasta tal tamaño que podría (y debería) dividirse.
GWT usa esto y lo llaman código DFN (Dead-for-now) . No hay mucha magia aquí. Solo tiene que definir manualmente cuando necesite una nueva pieza de código y, si el usuario lo necesita, simplemente llame a ese archivo.
¿Cómo, cuándo, dónde lo necesitarás?
Punto de referencia. Chrome tiene una gran herramienta de evaluación comparativa. Utilícelo extensivamente. Vea si tener solo un pequeño archivo javascript mejorará en gran medida la carga de esa página en particular. Si lo hace por todos los medios, comience a DFNing su código.
Aparte de eso, todo se trata de la percepción.
¡No dejes que el contenido salte!
Si tu página tiene imágenes, configura sus anchos y alturas desde el frente. Como la página se cargará con los elementos colocados justo donde se supone que deben estar, no habrá ajuste de contenido y el ajuste de la percepción de la velocidad del usuario aumentará.
Aplazar javascript!
Todas las bibliotecas principales pueden esperar a que se cargue la página antes de ejecutar javascript. Utilízalo jQuery''s va así $(document).ready(function(){ ... })
. No espera a analizar el código, pero hace que el código analizado se active exactamente cuando debería. Después de cargar la página, antes de cargar la imagen.
Cosas importantes a tener en cuenta:
- Asegúrese de que el cliente almacene en caché los archivos js (todos los demás se quedan cortos en comparación con este)
- Compila tu código con Closure Compiler
- Desinfle su código ; Es más rápido que Gziping (en ambos extremos)
Ejemplo de apache de caché:
// Set up caching on media files for 1 month
<FilesMatch "/.(gif|jpg|jpeg|png|swf|js|css)$">
ExpiresDefault A2629744
Header append Cache-Control "public, proxy-revalidate"
Header append Vary "Accept-Encoding: *"
</FilesMatch>
Apache ejemplo de desinflado:
// compresses all files for faster transfer
LoadModule deflate_module modules/mod_deflate.so
AddOutputFilterByType DEFLATE text/html text/plain text/xml font/opentype font/truetype font/woff
<FilesMatch "/.(js|css|html|htm|php|xml)$">
SetOutputFilter DEFLATE
</FilesMatch>
Y por último, y probablemente menos, sirva su Javascript desde un dominio sin cookies.
Y para mantener su pregunta enfocada, recuerde que cuando tenga el código DFN, tendrá varios archivos javascript más pequeños que, precisamente por estar divididos, no tendrán el nivel de compresión que Closure puede proporcionarle con uno solo. La suma de las partes no es igual a la totalidad en este escenario.
¡Espero eso ayude!