¿Quieres registrarte?

Carga dinámica de librerías Javascript con LibraryManager

Por: [Sheer]
25 de Diciembre del 2008
249 de clabLevel
Otros artículos de [Sheer]
3,656 visitas

Hace pocos meses me adentré en lo que envuelve Javascript y la web 2.0 con AJAX, viniendo de programar en ActionScript. Quise ser valiente y seguir utilizando el concepto de clase, pequeños módulos (o no), de código reutilizable y que facilitan el mantenimiento de forma considerable. Al conjunto de estos módulos se les llama librería.

Para importar una librería de una aplicación en tu página web, puedes escribir lo siguiente en el tag "head":

Código :

<script src="includes/javascript/Archivo1.js" type="text/javascript"></script>
<script src="includes/javascript/Archivo2.js" type="text/javascript"></script>
<script src="includes/javascript/Archivo3.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="includes/styles/estilo.css"/>

Ahora imagina que tienes un buen número de aplicaciones con sus correspondientes librerías y desconoces cuando las vas a necesitar. El código de arriba está muy bien si tienes previsto crear contenido estático, pero puedes necesitar cargar cierta aplicación en un momento dado, por eso utilizaremos la carga dinámica.

Una opción es incrustar el tag <script> mediante createElement/appendChild a <head>, pero corres el riesgo de que, en caso de que Archivo2 necesite instanciar a Archivo1, éste último todavía no se haya cargado. Por eso he creado LibraryManager, una clase en Javascript que facilita la carga dinámica haciendo uso de peticiones AJAX (comentar que he utilizado el Framework Prototype). Aquí el código:

Código :

var LibraryManager = Class.create({
    initialize: function(){
        var carpetaBase = "includes/";
        this._rutaArchivos = new Array(); // ruta según tipo de archivo (manejado por extensión)
        this._rutaArchivos["css"] = carpetaBase + "styles/";
        this._rutaArchivos["js"] = carpetaBase + "javascript/";
        this._archivosCargandose = new Array(); // archivos que actualmente se están cargando
        this._archivosCargados = new Array(); // archivos que ya se han cargado
    },
   /**
    * Método reiterativo. Carga un archivo por cada llamada.
    * @param {Object} libreria (Array) -> Listado de archivos a cagar
    * @param {Object} callback (Function) -> Se llamará esta función al terminar la carga de todos los archivos
    */
    cargar: function(libreria, callback){
        if (libreria.length == 0) 
            callback.call();
        else {
            // si no se ha cargado
            if (!this._archivosCargados[libreria.first()]) {
                var scope = this;
                // si ya se está cargando, esperar a que esté listo antes de continuar
                // (ésto es útil en caso de cargar múltiples librerías a la vez que requieran ese mismo archivo)
                if (this._archivosCargandose[libreria.first()]) {
                    var interval = setInterval(function(){
                        if (scope._archivosCargados[libreria.first()]) {
                            libreria.shift();
                            clearInterval(interval);
                            scope.cargar(libreria, callback);
                        }
                    }, 10);
                }
                else {
                    var tipo = libreria.first().split(".").last();
                    this._archivosCargandose[libreria.first()] = true;
                    switch (tipo) {
                        case "css":
                            var nodoCss = document.createElement('link');
                            with (nodoCss) {
                                type = 'text/css';
                                rel = 'stylesheet';
                                media = 'screen';
                            }
                            nodoCss.href = this._rutaArchivos[tipo] + libreria.first();
                            document.getElementsByTagName("head")[0].appendChild(nodoCss);
                            this._archivosCargados[libreria.first()] = true;
                            libreria.shift();
                            this.cargar(libreria, callback);
                            break;
                        case "js":
                            new Ajax.Request(this._rutaArchivos[tipo] + libreria.first(), {
                                method: 'get',
                                onComplete: function(){
                                    scope._archivosCargados[libreria.first()] = true;
                                    libreria.shift();
                                    scope.cargar(libreria, callback);
                                }
                            });
                            break;
                        default:
                            libreria.shift();
                            this.cargar(libreria, callback);
                    }
                }
            }
            // si ya se ha cargado
            else {
                libreria.shift();
                this.cargar(libreria, callback);
            }
        }
    }
});
var libraryManager = new LibraryManager();

Resumidamente, la clase distingue entre los archivos *.css y *.js. Los estilos los carga sin necesidad de hacer ninguna petición AJAX al no ser necesario. Hasta que no termina con un archivo, no pasa al siguiente. Controla que un archivo no se cargue más de una vez. Permite realizar cargas múltiples al mismo tiempo controlando si un archivo ya se está cargando (por ejemplo, si para otra aplicación ya se encuentra cargando ese archivo) esperando a que esté listo y continuar con el siguiente.

Para utilizarla solo debes importarla y cuando necesites hacer una carga, llamar a su método cargar (ya se crea una instancia llamada libraryManager en el propio archivo de la clase, por lo que no es necesario hacer nada más). Ejemplo:

Código :

var libreria1 = ["estilos.css","1.js", "2.js"];
function cargada(){
   alert("¡Librería lista!");
   // aquí se podría instanciar a la clase principal de la aplicación
}
libraryManager.cargar(libreria1.slice(), cargada);


Eso es todo por hoy. ¡Gracias por su atención y hasta la próxima! ^^

(Por supuesto, cualquier crítica constructiva será bienvenida)

Archivos de ejemplo: http://www.cristalab.com/images/tips/ajax/LibraryManager/LibraryManager.rar

Enviar a twitter Enviar a facebook


También te interesa


Etiquetas javascript ajax

Comentarios | Enviar un comentario
buenisimo, siendo muchos codigos esto me hace sentir como si fuera Visual Studio
Por: Siriö
El LibraryManager ejecuta el codigo que se encuentra dentro del archivo externo ".js", pero si tengo un prototipo o una funcion publica y deseo instanciar dicho prototipo o invocar la funcion punblica, el documento html no reconoce el elemento.
Es decir, sirve solamente si se ejecuta un codigo, de lo contrario no funciona. Tambien lo probe con el ejemplo que se encuentra en la pagina, y ejecuta el alert, pero ahora, si queremos invocar una funciona q ejecute dicho alert, no funciona.
Espero los comentario, muchas gracias.
Saludos.
Por: Hernan-blog

Hernan-blog :

El LibraryManager ejecuta el codigo que se encuentra dentro del archivo externo ".js", pero si tengo un prototipo o una funcion publica y deseo instanciar dicho prototipo o invocar la funcion punblica, el documento html no reconoce el elemento.
Es decir, sirve solamente si se ejecuta un codigo, de lo contrario no funciona. Tambien lo probe con el ejemplo que se encuentra en la pagina, y ejecuta el alert, pero ahora, si queremos invocar una funciona q ejecute dicho alert, no funciona.
Espero los comentario, muchas gracias.
Saludos.


Cierto. Lo que sucede es que todo aquello que crees dentro del js, será declarado, si no se le indica, en el objeto Ajax.Request que lo llama, por lo que es imprescindible especificarle el scope a las funciones que creemos dentro. Por ejemplo, si queremos crear una función global, le indicaremos donde debe crearla de esta manera:

window.miFuncion = function() {
alert("ya soy global!");
}
Por: [Sheer]
como haríamos para modificar la librería para que funcione con JQuery???
Por: ingjuanfelipe
Deja un comentario
IMPORTANTE

Recuerda ser respetuoso, no insultes a otras personas, ni uses palabrotas, hay una persona al otro lado de la pantalla.

Habla bien, NO ESCRIBAS EN MAYUSCULA TODO, no escribas como en un SMS, evita cosas como "ke", "x q" y demás abreviaciones.

Aquí funcionan las etiquetas de los foros, puedes usar [b] para negrita, [img] para las imágenes, [url] para los enlaces, etc.

Si tienes preguntas técnicas, envíalas mejor al foro.