2012-06-11 17 views
37

Nos encanta RequireJS y AMD durante el desarrollo, donde podemos editar un módulo, presionar "volver a cargar" en nuestro navegador e inmediatamente ver el resultado. Pero cuando llega el momento de concatenar nuestros módulos en un único archivo para la implementación de producción, aparentemente tiene que haber un cargador AMD presente, ya sea que el cargador sea RequireJS o su socio menor "almond" como se explica aquí:¿Por qué los módulos concatenados RequireJS AMD necesitan un cargador?

http://requirejs.org/docs/faq-optimization.html#wrap

Mi confusión es: ¿por qué es necesario un cargador? A menos que tenga circunstancias inusuales que lo hagan necesario para hacer llamadas require() dentro de sus módulos, parecería que una serie de módulos AMD podrían concatenarse sin un cargador presente. El ejemplo más simple posible sería un par de módulos como el siguiente.

ModA.js:

define([], function() { 
    return {a: 1}; 
}); 

ModB.js:

define(['ModA'], function(A) { 
    return {b : 2}; 
}); 

Dados estos dos módulos, parece que un concatenator podría producir simplemente el siguiente texto, y no una carga para el servidor de producción o navegador con el ancho de banda adicional o el cálculo requerido por RequireJS o Almond.

Me imagino a un concatenator que produce (y estoy usando Chevron-citas «» para mostrar donde los fragmentos de los dos módulos anteriores se han insertado):

Esto, por lo lejos que pueda ver, reproduciría correctamente la semántica de AMD, con un mínimo de pegamento extraño JavaScript. ¿Hay tal concatenación disponible? Si no, sería un tonto por pensar que debería escribir uno: ¿hay realmente muy pocas bases de código que consistan en módulos simples y limpios escritos con define() y que nunca necesiten más llamadas al require() que inicien más adelante búsquedas asíncronas de código?

+1

¿Cómo resolvió este problema? Descubrí que al usar almendra, el archivo min es más grande por 3k que el archivo concatenado (9K vs 6K). – Naor

Respuesta

14

Un optimizador de AMD tiene el alcance para optimizar más que el número de archivos que se descargarán, también puede optimizar la cantidad de módulos cargados en la memoria.

Por ejemplo, si tiene 10 módulos y puede optimizarlos en 1 archivo, entonces se habrá guardado 9 descargas.

Si Page1 usa los 10 módulos, eso es genial. ¿Pero qué pasa si Page2 solo usa 1? Un cargador AMD puede retrasar la ejecución de la 'función de fábrica' hasta que un módulo sea require 'd. Por lo tanto, Page2 solo activa una sola 'función de fábrica' para ejecutar.

Si cada módulo consume 100kb de memoria al ser require 'd, entonces un marco AMD que tenga optimización en tiempo de ejecución también nos ahorrará 900kb de memoria en la Página2.

Un ejemplo de esto podría ser un cuadro de diálogo 'Acerca del cuadro'. Donde la misma ejecución se retrasa hasta el último segundo, ya que no se accederá en el 99% de los casos. P.ej. (En la sintaxis de jQuery suelto):

aboutBoxBtn.click(function() { 
    require(['aboutBox'], function (aboutBox) { 
     aboutBox.show(); 
    } 
}); 

Se ahorra el gasto de crear los objetos y JS DOM asociado con el 'Acerca de la caja' hasta que esté seguro de que es necesario.

Para obtener más información, consulte Delay executing defines until first require para la toma de requirejs en esto.

+1

¡Interesante! Entonces, si entiendo lo que estás diciendo, estás postulando un código que crea objetos y modifica el DOM * simplemente como un efecto secundario de ser requerido *, ¿es correcto? No hubiera pensado en eso, y si esa práctica es común, entonces bien podría haberse dado cuenta de las razones por las que a los programadores de JS les gusta tener el cargador AMD allí en producción. Probablemente debido a mi experiencia en Python, ninguno de mis códigos se ejecuta alguna vez cuando se importa; simplemente devuelve un objeto lleno de funciones para llamar cuando finalmente se necesitan sus efectos secundarios. –

+0

Su ejemplo sobre el uso de memoria a menudo se confunde con la sobrecarga de E/S. Para una caja como esta parece que sería una victoria cargar antes pero diferir la inicialización para que pueda ahorrar memoria y configuración sin un gran golpe de latencia interactiva. –

+0

@Chris, estoy de acuerdo con sus puntos, pero solo quería presentar un caso por tener un cargador AMD presente en tiempo de ejecución. Es posible que esté preocupado por la ejecución de demasiados códigos en el inicio, mientras que podría estar preocupado por la latencia. Además de los casos triviales, no creo que haya una solución única para todos cuando se trata de rendimiento. Y no habría un golpe de latencia en mi ejemplo, ya que todo el JS se ha cargado, simplemente no 'ejecutado'. –

1

El único beneficio real es si utiliza módulos en todas las secciones, por lo que los módulos de almacenamiento en caché tienen un beneficio independiente.

0

En caso de que compile su código con require.js en un solo archivo grande para producción, puede usar almond.js para reemplazar completamente.

Almond solo maneja la gestión de referencias del módulo, no la carga en sí misma, que ya no es necesaria.

tener cuidado con el restrictions almendras impone con el fin de trabajar

0

No hay ninguna razón por la que no podría ser una herramienta de construcción como la que usted propone.

La última vez * Miré la salida del optimizador, convirtió los módulos a módulos con nombre explícito y luego los combinó. Depende de sí mismo para asegurarse de que las funciones de fábrica se llamaron en el orden correcto y que se pasaron los objetos del módulo adecuado. Para construir una herramienta como usted quiere, tendría que linealizar explícitamente los módulos, no imposible, pero mucho más trabajo. Esa es probablemente la razón por la que no se ha hecho.

Creo ** que el optimizador tiene una función para incluir automáticamente requerirse a sí mismo (o almendra) en el archivo construido, por lo que solo tiene que tener una descarga. Eso sería más grande que el resultado de la herramienta de compilación que desea, pero por lo demás igual.

Si había una herramienta de construcción que produjo el tipo de salida que está pidiendo, habría que tener más cuidado, en el caso de la sincrónica require, el uso de exports vez de regreso, y cualquier otro CommonJS compatibilidad caracteristicas.

* Eso fue hace unos años. 2010, creo.

** Pero parece que no puede encontrarlo ahora.

1

Tenía la misma necesidad, así que creé un simple "compilador" de AMD para ese propósito que hace justamente eso. Puede obtenerlo en https://github.com/amitayh/amd-compiler

Tenga en cuenta que le faltan muchas características, pero cumple su función (al menos para mí). Siéntase libre de contribuir a la base de código.

Cuestiones relacionadas