2011-02-06 5 views
137

¿Cuál es la diferencia entre usar Require.JS y simplemente crear un elemento <script> en el DOM?¿Cuál es la diferencia entre Require.js y simplemente crear un elemento <script> en el DOM?

Mi comprensión de Require.JS es que ofrece la posibilidad de cargar dependencias, pero ¿no se puede hacer simplemente creando un elemento <script> que cargue el archivo JS externo necesario?

Por ejemplo, supongamos que tengo la función doStuff(), que requiere la función needMe(). doStuff() está en el archivo externo do_stuff.js, mientras que needMe() está en el archivo externo need_me.js.

Hacer esto de la manera Require.JS:

define(['need_me'],function(){ 
    function doStuff(){ 
     //do some stuff 
     needMe(); 
     //do some more stuff 
    } 
}); 

Hacer esto simplemente creando un elemento de script:

function doStuff(){ 
    var scriptElement = document.createElement('script'); 
    scriptElement.src = 'need_me.js'; 
    scriptElement.type = 'text/javascript'; 
    document.getElementsByTagName('head')[0].appendChild(scriptElement); 

    //do some stuff 
    needMe(); 
    //do some more stuff 
} 

Ambos trabajo. Sin embargo, la segunda versión no requiere que cargue toda la biblioteca Require.js. Realmente no veo ninguna diferencia funcional ...

+1

¿qué pasa con el almacenamiento en caché del navegador, hace RequireJS interfieren con ella? –

+0

Estoy volviendo a abrir esto porque está pidiendo la diferencia entre dos cosas muy similares. * Puede * ser respondido objetivamente, y no veo en qué opinión se vincula. – RamenChef

Respuesta

43

Aquí está el artículo agradable en ajaxian.com de por qué usarlo:

RequireJS: Asynchronous JavaScript loading

  • algún tipo de # include/import/requerir
  • capacidad de cargar dependencias anidadas
  • facilidad de uso para el desarrollador, pero entonces el respaldo de una herramienta de optimización que ayuda a la implementación
+2

He leído eso, pero ahora que lo pienso más, me doy cuenta de que la idea de las dependencias anidadas no se puede lograr escribiendo simplemente las etiquetas

52

¿Qué ventajas ofrece Require.JS en comparación con simplemente crear un elemento en el DOM?

En su ejemplo, se está creando la etiqueta script de forma asíncrona, lo que significa que su función needMe() sería invocado antes el archivo need_me.js finaliza la carga. Esto da como resultado excepciones no detectadas donde su función no está definida.

En cambio, para hacer lo que está sugiriendo realmente el trabajo, que había necesidad de hacer algo como esto:

function doStuff(){ 
    var scriptElement = document.createElement('script'); 
    scriptElement.src = 'need_me.js'; 
    scriptElement.type = 'text/javascript'; 

    scriptElement.addEventListener("load", 
     function() { 
      console.log("script loaded - now it's safe to use it!"); 

      // do some stuff 
      needMe(); 
      //do some more stuff 

     }, false); 

    document.getElementsByTagName('head')[0].appendChild(scriptElement); 

} 

Podría decirse que puede o no puede ser mejor usar un gestor de paquetes como RequireJS o utilizar una estrategia de JavaScript puro como se demostró anteriormente. Si bien su aplicación web puede cargarse más rápido, la funcionalidad y las funciones de invocación en el sitio serían más lentas, ya que implicaría esperar a que se carguen los recursos antes de que se pueda realizar esa acción.

Si una aplicación web se crea como una aplicación de una sola página, considere que las personas no volverán a cargar la página muy a menudo. En estos casos, precargar todo ayudaría a que la experiencia parezca más rápida cuando en realidad usando la aplicación. En estos casos, tiene razón, uno puede simplemente cargar todos los recursos simplemente incluyendo las etiquetas de script en el encabezado o cuerpo de la página.

Sin embargo, si se crea un sitio web o una aplicación web que sigue el modelo más tradicional donde se realiza una transición de página a página, lo que hace que los recursos se vuelvan a cargar, un enfoque de carga diferida puede ayudar a acelerar estas transiciones.

9

Algunas otras razones por las que usar muy puntiaguda RequireJS tiene sentido:

  1. La gestión de sus propias dependencias rápidamente se desmorona para proyectos de tamaño considerable.
  2. Puede tener tantos archivos pequeños como desee, y no tiene que preocuparse de hacer un seguimiento de las dependencias ni de cargar el pedido.
  3. RequireJS hace posible escribir una aplicación modular completa sin tocar el objeto ventana.

Tomado de rmurphey's comments here in this Gist.

Las capas de abstracción pueden ser una pesadilla para aprender y adaptarse, pero cuando tiene un propósito y lo hace bien, simplemente tiene sentido.

+9

Aún tiene que administrar todos los que requieren y definir declaraciones, archivos de configuración, colisiones con otros sistemas y bibliotecas que no han implementado la especificación AMD, etc. Intenté usar Require.JS en un proyecto node-webkit y Require. JS luchó conmigo en cada paso del camino ... Contraste eso con simplemente ordenar secuencias de comandos de cierta manera ... Por supuesto, obtienes carga lenta con Require.JS, por lo que intenté hacerlo funcionar. :) – jmort253

+0

Estoy totalmente de acuerdo con @jmort253, fue una lucha al principio, pero ahora me gusta mucho. ¡Los tres puntos son correctos! Y AMDificar una biblioteca no debería ser tan difícil ... o usar la cuña. – Legends

0

Aquí hay un ejemplo más concreto.

Estoy trabajando en un proyecto con 60 archivos. Tenemos 2 modos diferentes de ejecutarlo.

  1. Cargue una versión concatenada, 1 archivo grande. (Producción)

  2. Cargar los 60 archivos (desarrollo)

Estamos utilizando un cargador por lo que simplemente tenemos una secuencia de comandos en la página web

<script src="loader.js"></script> 

Ese defecto en modo # 1 (cargando el único archivo concatenado grande). Para ejecutar el modo en # 2 (archivos separados) configuramos algunos indicadores. Podría ser cualquier cosa. Una clave en la cadena de consulta. En este ejemplo que acabamos de hacer esto

<script>useDebugVersion = true;</script> 
<script src="loader.js"></script> 

loader.js ve algo como esto

if (useDebugVersion) { 
    injectScript("app.js"); 
    injectScript("somelib.js"); 
    injectScript("someotherlib.js"); 
    injectScript("anotherlib.js"); 
    ... repeat for 60 files ... 
} else { 
    injectScript("large-concatinated.js"); 
} 

La escritura de la estructura es sólo un archivo .sh que tiene este aspecto

cat > large-concantinated.js app.js somelib.js someotherlib.js anotherlib.js 

etc. ..

Si se agrega un nuevo archivo, es probable que estemos usando el modo # 2, ya que estamos haciendo el desarrollo, tenemos que agregar un injectScript("somenewfile.js") línea a loader.js

Luego, para la producción, también tenemos que agregar somenewfile.js a nuestro script de compilación. Un paso que a menudo olvidamos y luego recibimos mensajes de error.

Al cambiar a AMD no es necesario editar 2 archivos. El problema de mantener loader.js y la secuencia de comandos de compilación sincronizados desaparece. Usando r.js o webpack que sólo puede leer el código para construir large-concantinated.js

También puede hacer frente a las dependencias, por ejemplo, teníamos 2 archivos lib1.js y LIB2.js cargado de esta manera

injectScript("lib1.js"); 
injectScript("lib2.js"); 

lib2 needs lib1. Tiene código dentro que hace algo como

lib1Api.installPlugin(...); 

Pero a medida que los scripts inyectados se cargan de forma asíncrona no hay garantía de que van a cargar en el orden correcto. Estos 2 guiones no son textos de AMD, pero utilizando require.js podemos decir que sus dependencias

require.config({ 
    paths: { 
     lib1: './path/to/lib1', 
     lib2: './path/to/lib2', 
    }, 
    shim: { 
     lib1: { 
      "exports": 'lib1Api', 
     }, 
     lib2: { 
      "deps": ["lib1"], 
     }, 
    } 
}); 

que nuestro módulo que utiliza LIB1 hacemos esto

define(['lib1'], function(lib1Api) { 
    lib1Api.doSomething(...); 
}); 

Ahora require.js inyectará los guiones de us y no inyectará lib2 hasta que se haya cargado lib1 ya que le dijimos que lib2 depende de lib1. Tampoco iniciará nuestro módulo que usa lib1 hasta que se hayan cargado tanto lib2 como lib1.

Esto hace que el desarrollo sea agradable (sin pasos de compilación, sin preocuparse por el orden de carga) y hace que la producción sea agradable (no es necesario actualizar un script de compilación para cada script agregado).

Como bonificación adicional, podemos usar el plugin babel de webpack para ejecutar Babel sobre el código para navegadores antiguos y tampoco tenemos que mantener ese script de compilación.

Tenga en cuenta que si Chrome (nuestro navegador de elección) comenzó a admitir import de verdad, probablemente cambiaríamos a eso para el desarrollo, pero eso realmente no cambiaría nada. Todavía podríamos usar el paquete web para hacer un archivo concatenado y podríamos usarlo ejecutando babel sobre el código para todos los navegadores.

Todo esto se gana por no utilizar las etiquetas de secuencia de comandos y el uso de AMD

Cuestiones relacionadas