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

138

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

Entiendo que Require.JS es que ofrece la capacidad de cargar dependencias, pero ¿no puede hacerse simplemente creando un <script>elemento 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 needMe()está en el archivo externo need_me.js.

Haciendo 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 de estos trabajos. Sin embargo, la segunda versión no requiere que cargue toda la biblioteca Require.js. Realmente no veo ninguna diferencia funcional ...

maxedison
fuente
1
¿Qué pasa con el almacenamiento en caché del navegador, requirejs interfiere con él?
Muhammad Umer
Estoy reabriendo esto porque está pidiendo la diferencia entre dos cosas muy similares. Se puede responder objetivamente y, por cierto, no veo dónde se vincula la opinión.
RamenChef

Respuestas:

43

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

RequireJS: carga asincrónica de JavaScript

  • algún tipo de # incluir / importar / requerir
  • capacidad de cargar dependencias anidadas
  • facilidad de uso para el desarrollador pero luego respaldada por una herramienta de optimización que ayuda a la implementación
Sarfraz
fuente
2
Los había leído, pero ahora que lo pienso más, me doy cuenta de que la idea de dependencias anidadas no se puede lograr simplemente escribiendo etiquetas <script>. Gracias.
maxedison
37
La "facilidad de uso para el desarrollador" no podría estar más lejos de la realidad. Definitivamente tiene una curva de aprendizaje empinada para usted y cualquier otra persona que vaya a trabajar en ese proyecto.
Sahat Yalkabov
3
@TwilightPony Considero que no soy tan brillante y requiero no fue realmente algo difícil de conseguir para mí. Elimina la necesidad de preocuparse por las dependencias y acelera la página. Su código se vuelve más en línea con la programación del lado del servidor en la forma en que declara sus dependencias, lo que personalmente considero refrescante y simple. La sintaxis era mínima y el diseño ajustaba el cierre y luego establece la hoja de ruta para la producción para combinar fácilmente sus scripts. Además de esa depuración es como las declaraciones estáticas. No estoy seguro de qué es más fácil que eso. Mucho más difícil a la inversa como lo he hecho a la inversa.
Jason Sebring
Estoy luchando. Especialmente con módulos que intentan unirse a objetos globales. (Reaccionar módulos) ...
dorado
1
Los comentarios en esa página realmente me dejaron con la sensación de que uno debería huir y no exigir. Especialmente el que está cerca del fondo que enlaza con stevesouders.com/tests/require.php
Dave Kanter
52

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

En su ejemplo, está creando la etiqueta de script de forma asincrónica, lo que significa que su needMe()función se invocará antes de que el archivo need_me.js termine de cargarse. Esto da como resultado excepciones no detectadas donde su función no está definida.

En cambio, para hacer que lo que sugieres realmente funcione, deberías 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 ser mejor usar un administrador de paquetes como RequireJS o utilizar una estrategia de JavaScript puro como se demostró anteriormente. Si bien su aplicación web puede cargar más rápido, invocar la funcionalidad y las características en el sitio sería más lenta, 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 con mucha frecuencia. En estos casos, precargar todo ayudaría a que la experiencia parezca más rápida cuando se usa la aplicación. En estos casos, tiene razón, uno simplemente puede cargar todos los recursos simplemente al incluir 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 en el que se realiza una transición de una página a otra, lo que hace que los recursos se vuelvan a cargar, un enfoque de carga diferida puede ayudar a acelerar estas transiciones.

jmort253
fuente
10

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

  1. Administrar sus propias dependencias se desmorona rápidamente para proyectos importantes.
  2. Puede tener tantos archivos pequeños como desee y no tiene que preocuparse por hacer un seguimiento de las dependencias o el orden de carga.
  3. RequireJS hace posible escribir una aplicación modular completa sin tocar el objeto de la ventana.

Tomado de los comentarios de rmurphey aquí en este Gist .

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

girls_can_code_too
fuente
9
Todavía tiene que administrar todos los requisitos 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 de nodo-webkit y Require.JS peleé conmigo en cada paso del camino ... Contrasta eso con simplemente ordenar scripts de cierta manera ... Por supuesto, obtienes una carga perezosa con Require.JS, por eso intenté hacerlo funcionar. :)
jmort253
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.
Leyendas
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. Cargue los 60 archivos (desarrollo)

Estamos usando un cargador, así que solo tenemos un script en la página web

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

El valor predeterminado es el modo n. ° 1 (cargar el archivo concatenado grande). Para ejecutar el modo in # 2 (archivos separados) configuramos alguna bandera. Podría ser cualquier cosa. Una clave en la cadena de consulta. En este ejemplo solo hacemos esto

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

loader.js se parece a esto

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

El script de compilación es solo un archivo .sh que se ve así

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

etc ...

Si se agrega un nuevo archivo, probablemente injectScript("somenewfile.js")usaremos el modo n. ° 2, ya que estamos desarrollando, tenemos que agregar una 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 tenemos que editar 2 archivos. El problema de mantener loader.js y el script de compilación sincronizado desaparece. Usando r.jso webpacksimplemente puede leer el código para construirlarge-concantinated.js

También puede tratar dependencias, por ejemplo, teníamos 2 archivos lib1.js y lib2.js cargados así

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

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

lib1Api.installPlugin(...);

Pero como los scripts inyectados se cargan de forma asincrónica, no hay garantía de que se carguen en el orden correcto. Estas 2 secuencias de comandos no son secuencias de comandos AMD, pero utilizando require.js podemos decirle sus dependencias

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

Yo nuestro módulo que usa lib1 hacemos esto

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

Ahora require.js inyectará los scripts por nosotros y no inyectará lib2 hasta que lib1 se haya cargado, ya que dijimos que lib2 depende de lib1. Tampoco iniciará nuestro módulo que usa lib1 hasta que se hayan cargado lib2 y lib1.

Esto hace que el desarrollo sea agradable (sin paso 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 beneficio adicional, podemos usar el complemento babel de webpack para ejecutar babel sobre el código de los navegadores más antiguos y, de nuevo, tampoco tenemos que mantener ese script de compilación.

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

Todo esto se obtiene al no usar etiquetas de script y usar AMD

gman
fuente