jQuery.getScript() y AMD (Asynchronous module definition)

En el mes de Marzo escribí un post sobre cómo utilizar Requirejs para la carga de módulos en JavaScript. Siguiendo esta línea, me gustaría hablaros de cómo podemos obtener un resultado similar con JQuery y su método getScript.

JQuery.getScript()

Tal y como se indica en la documentación de JQuery, se trata de un método que permite la carga de un archivo ubicado en el servidor a través de una petición GET. A grandes rasgos es lo que necesitamos para la carga de módulos en JavaScript.
Siguiendo el ejemplo del post con RequireJS, lo que queremos conseguir es lo siguiente:

<!DOCTYPE html>
<html>
<head>
    <title>JQuery - GetScript</title>
</head>
<body>
    <section>
        <input type="text" id="msg" />
        <select id="type">
            <option>info</option>
            <option>warning</option>
            <option>error</option>
        </select>
        <button id="btn">Send</button>
    </section>
    <script src="Scripts/jquery-2.0.3.min.js"></script>
    <!--<script src="App/3.log.js"></script>
    <script src="App/2.trace.js"></script>-->
    <script src="App/1.boot.js"></script>
</body>
</html>

Al final, la intención es evitar algo a lo que estamos muy acostumbrados: tener que referenciar en la carga de una página todos los archivos JavaScript (¡y en orden!), para que estén listos cuando se solicite la funcionalidad relacionada con ellos. En este ejemplo, utilizaremos el archivo 1.boot.js como punto de entrada:

$(function () {
    $("#btn").click(function () {
        console.log("boot.js");
        $.getScript('/App/2.trace.js', function (script, textStatus, jqXHR) {
            var msg = $("#msg").val(),
                type = $("#type").val();

            console.log("calling trace.message");
            trace.message(msg, type);

        });
    });
});

Cuando el documento está listo, añadimos un manejador al evento click del botón que ejecutará todo el proceso. Si nos fijamos en el manejador, antes de realizar cualquier operación, utilizamos $.getScript donde le pasamos la ruta del archivo que queremos cargar y la función de callback que se ejecutará si la carga ha tenido éxito. Dependiendo de cómo se haya implementando el módulo, el mismo se ejecutará una vez cargado o, por el contrario, deberemos hacerlo de forma manual. En este ejemplo estamos trabajando con singletons, por lo que la carga del código será transparente para nosotros. El callback recibe el script que acaba de cargar, el estado de la carga (“success”) y el objeto que realizó la petición. Este script será cargado en el contexto global por lo que debemos tener cuidado con el contenido a cargar para evitar conflictos (recomendable el uso de namespaces). Veamos qué acabamos de solicitar a través de getScript:

var trace = function () {
    console.log("trace.js loaded");
    return {
        message: function (msg, type) {
            $.getScript('/App/3.log.js', function (script, textStatus, jqXHR) {
                switch (type) {
                    case "info":
                        log.info(msg);
                        break;
                    case "warning":
                        log.warning(msg);
                        break;
                    case "error":
                        log.error(msg);
                        break;
                    default:
                        return;
                }

            });
        }
    };
}();

El código es bastante sencillo: lo primero que hacemos es mostrar por consola un mensaje que nos alerte de que el script ha sido cargado y exponemos un método llamado mensaje que, a su vez, solicitará un segundo script para poder ejecutar los métodos que dependen de la variable log. De esta forma, sólo se cargará el siguiente script cuando la función que realmente lo necesita vaya a hacer uso de él.

Por último, el módulo log no tiene dependencias de ningún otro:

var log = function () {
    console.log("log.js loaded");

    var
        info = function (msg) {
            console.log(msg);
        },
        warning = function (msg) {
            console.warn(msg);
        },
        error = function (msg) {
            console.error(msg);
        };

    return {
        info: info,
        warning: warning,
        error: error
    };

}();

Para comprobar que está funcionando correctamente, he habilitado en la consola de Chrome las trazas de las peticiones realizadas para poder ver el flujo completo desde la misma:

Log XMLHttpRequests

El resultado que esperamos sería el siguiente:

JQuery getScript Test

Lo cierto es que es una versión muy light de lo que podemos llegar a hacer con RequireJS, el cual es por supuesto mucho más potente en este sentido. Sin embargo, la mayoría de las aplicaciones a día de hoy utilizan JQuery como base para su desarrollo en el lado del cliente y, para casos donde no hagamos uso de muchas dependencias, puede ser un buen acercamiento y una mejora tanto en el rendimiento general de la aplicación como en la administración de nuestros scripts.

Espero que haya sido de utilidad 😀

¡Saludos!