Contenido


Cargue bibliotecas JavaScript externas bajo demanda con Dojo 1.5

Y disminuya el tiempo de carga de las aplicaciones web

Comments

Visión general

El kit de herramientas JavaScript de Dojo es una excelente biblioteca que ofrece casi todos los requerimientos para crear aplicaciones de Internet enriquecidas. Sin embargo, las bibliotecas JavaScript externas a veces deben utilizarse para requerimientos avanzados o de nicho de una aplicación. En esos casos, puede agregar la biblioteca a la aplicación usando el método HTML estándar, con el cual se agrega una etiqueta <script> adicional. Este procedimiento puede ocasionar una reducción del rendimiento. Afortunadamente, Dojo ofrece una alternativa a este método: dojo.io.script.

En este artículo, conocerá las ventajas y las desventajas del enfoque dojo.io.script. En el código de ejemplo, se muestra cómo evitar algunos de los errores más grandes. Puede descargar el código fuente utilizado en este artículo.

Dos métodos para cargar bibliotecas JavaScript externas

En la Tabla 1, se comparan dos métodos para cargar bibliotecas JavaScript externas.

Tabla 1. Etiqueta <script> y dojo.io.script
Etiqueta <script>dojo.io.script
Reducción de la velocidad de carga de una páginaPotencialmente alta; cuando se carga la biblioteca, se bloquea la inicialización de la página.Nula; la biblioteca se carga bajo demanda.
Reducción de la velocidad del códigoNula.El uso inicial provocará una demora mientras se carga la biblioteca.
ComplejidadSimple. Todos los códigos pueden utilizar la biblioteca de forma inmediata.Compleja. El código debe solicitar la biblioteca de forma inteligente y esperar a que esta se cargue.

El método dojo.io.script ofrece ventajas claras para las aplicaciones que solo utilizan una biblioteca externa en una rama de código específica. Y la carga diferida ofrece ventajas especiales. El método de la etiqueta <script> tiene la ventaja atractiva de ser simple cuando se utiliza la biblioteca en toda la aplicación. Es posible que prefiera dojo.io.script , ya que proporciona un tiempo de carga de página menor en todos los casos.

Uso de dojo.io.script

En el Listado 1, se muestra un ejemplo simple donde se utiliza dojo.io.script para cargar de forma asincrónica una sola biblioteca.

Listado 1. Invocación única de dojo.io.script
                dojo.require("dojo.io.script");

dojo.addOnLoad(function() {
    // Load the library.
    // dojo.io.script.get is asynchronous, so we get back a dojo.Deferred object
    var deferred = dojo.io.script.get({url : "url_of_library.js"});

    // Handle the deferred callback paths
    deferred.then(function() {
        // This function is called when the library is successfully loaded
        // You should place your application code that depends on the library here
    }, function() {
        // This function is called if an error occurs
    });
});

Uso avanzado

En el caso de las bibliotecas que tienen muchos módulos con dependencias entre módulos, es posible que deba encadenar invocaciones – similares a las descritas anteriormente – para obtener el comportamiento deseado durante el proceso de carga. En el Listado 2, se muestra un ejemplo más avanzado con invocaciones encadenadas.

Listado 2. Invocaciones encadenadas de dojo.io.script
 dojo.require("dojo.io.script");

dojo.addOnLoad(function() {
    // Load a JavaScript library consisting of two modules
    // We construct a partial function to load the second module; 
    // This simplifies the code path
    var deferred = dojo.io.script.get({url : "url_of_first_module.js"})
        .then(dojo.hitch(dojo.io.script, 'get', {url : "url_of_second_module.js"}));
    
    // Deferred handling goes here 
});

Administración de la complejidad

Cuando se cargan bibliotecas con muchos módulos con dojo.io.script o cuando se usan bibliotecas en diferentes ubicaciones del código, la administración de dojo.io.script y de los objetos diferidos resultantes puede ser compleja. Con los puntos de uso múltiple, se debe evitar particularmente que un módulo se cargue dos veces.

Si carga bibliotecas con muchos módulos o usa bibliotecas en diversas ubicaciones, considere usar métodos intermediarios.

libproxy

El método libproxy administra las dependencias entre módulos y asegura que los módulos se carguen solo una vez. En el código de muestra del Listado 3, se muestra cómo usar libproxy.

Listado 3. Uso de libproxy (libproxy_example.html)
dojo.require("proxy.jsv");

dojo.addOnLoad(function() {
    var jsvProxy = new proxy.jsv();
    
    jsvProxy.load('json-schema-draft-01').then(function() {
        // At this point, the JSV module for validating against draft 1 has been loaded.
        alert("loaded JSV draft 1");
    });
});

En el Listado 4, se muestra cómo usar libproxy para encapsular la carga de la biblioteca JSON Schema Validator (JSV) de Gary Court.

Listado 4. Carga encapsulada de la biblioteca JSV (proxy/jsv.js)
dojo.provide("proxy.jsv");

dojo.require("com.ibm.developerworks.libproxy");

/**
 * 
 */
dojo.declare("proxy.jsv", [com.ibm.developerworks.libproxy], {

    /**
     * In this file, we define the structure of our library,
     * and its inter-module dependencies
     */
    constructor : function() {
        var jsvRoot = "https://raw.github.com/garycourt/JSV/master/lib";
      
        this.modules = {
            '_uri' : { 
                sources : [{url : jsvRoot + "/uri/uri.js"}]
            },
            'base' : { 
                sources : [{url : jsvRoot + "/jsv.js"}], 
                deps : ['_uri']
            },
            'json-schema-draft-01' : { 
                sources : [{url : jsvRoot + "/json-schema-draft-01.js"}], 
                deps: ['base']
            },
            'json-schema-draft-02' : { 
                sources : [{url : jsvRoot + "/json-schema-draft-02.js"}], 
                deps: ['base'] 
            },
            'json-schema-draft-03' : { 
                sources : [{url : jsvRoot + "/json-schema-draft-03.js"}], 
                deps: ['base'] 
            }
        };
    }
    
});

En el Listado 5, se muestra el código libproxy.

Listado 5. Implementación básica para el encapsulado de bibliotecas (com/ibm/developerworks/libproxy.js)
dojo.provide("com.ibm.developerworks.libproxy");

dojo.require("dojo.io.script");
dojo.require("dojo.DeferredList");

/**
 * Do not directly use this class; instead, extend it and redefine the
 * modules field in the constructor
 */
dojo.declare("com.ibm.developerworks.libproxy", [], {

    constructor : function() {
        this._moduleDeferreds = [];
    },

    /**
     * Holds the modules of the library (and optional references to their
     * dependencies).
     * 
     * NB: 'sources' and 'deps' arrays will be loaded in parallel. If you need
     * to serialise this, add another module layer. ie. uri.js MUST be loaded
     * before jsv.js below
     * 
     * The 'sources' array holds objects that are passed in their entirety to
     * dojo.io.script.get()
     * 
     * Example, { 'module1Ref': { sources: [{ url: "module1.js" }] },
     * 'module2Ref': { sources: [{ url: "module2.js" }], deps: ['module1'] } };
     */
    modules : null,

    /**
     * Returns a dojo.Deferred object whose callback/errback fires when the
     * module is ready for use. Callback chain will contain the module
     * reference.
     * 
     * Example usage: load('module2').then(function() {});
     */
    load : function(/* String */moduleRef) {
        var F = this.declaredClass + ".";
        console.debug(F + "load()", arguments);

        // Check cache - have we loaded this library module before?
        if (this._moduleDeferreds[moduleRef]) {
            return this._moduleDeferreds[moduleRef];
        }

        // Create a new deferred and cache it
        var deferred = this._moduleDeferreds[moduleRef] = new dojo.Deferred();

        var module = this.modules[moduleRef];
        if (module) {
            deferred.callback(moduleRef);
            if (module.deps) {
                // Load dependencies in parallel
                deferred = deferred.then(dojo.hitch(this,
                        function(/* Array */dependencies) {
                            var defs = dojo.map(dependencies, dojo.hitch(this,
                                    'load'));
                            return new dojo.DeferredList(defs, false, true);
                        }, module.deps));
            }
            // Load sources in parallel
            deferred = deferred.then(dojo.hitch(this,
                    function(/* Array */sources) {
                        var defs = dojo.map(sources, dojo.hitch(dojo.io.script,
                                'get'));
                        return new dojo.DeferredList(defs, false, true);
                    }, module.sources));
        } else {
            deferred.errback("Unknown module reference.");
        }

        return deferred;
    }
});

Resumen

La administración del tiempo de carga de una página cuando utiliza muchas bibliotecas y kits de herramientas JavaScript puede convertirse rápidamente en un problema. En este artículo, conoció una alternativa a las etiquetas <script>. Puede usar el recurso dojo.io.script de Dojo para acelerar los tiempos de carga de una página cargando bibliotecas de forma diferida. Ante la complejidad presentada por este enfoque, aprendió a usar libproxy como intermediario para administrar las dependencias y las cargas.


Recursos para Descargar


Temas relacionados


Comentarios

Inicie Sesión o Regístrese para agregar comentarios.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=90
Zone=WebSphere
ArticleID=829936
ArticleTitle=Cargue bibliotecas JavaScript externas bajo demanda con Dojo 1.5
publish-date=08142012