Загрузка внешних JavaScript-библиотек по требованию с помощью Dojo 1.5

Уменьшение времени загрузки Web-приложений

Dojo – это замечательная библиотека для создания функционально насыщенных интернет-приложений. Однако сложные Web 2.0-приложения часто требуют более одной JavaScript-библиотеки, а загрузка нескольких библиотек при визуализации страницы может снизить производительность. В данной статье рассказывается, как использовать метод dojo.io.script библиотеки Dojo для асинхронной загрузки JavaScript-библиотек по требованию. Пример исходного кода поможет аккуратно "упаковать" процедуру загрузки внешних JavaScript-библиотек.

Ник Мейнард, консультант по технологиям Web 2.0, IBM

Ник Мейнард (Nick Maynard) работает в группе Business Solutions Team подразделения IBM Software Lab в Херсли (Великобритания). Специализируется на Dojo, Ajax, Web-программировании, Web-сервисах и Linux. Связаться с ним можно по адресу nick.maynard@uk.ibm.com.



21.06.2012

Обзор

Пакет инструментальных программ JavaScript Dojo – это отличная библиотека, удовлетворяющая большинство требований к созданию функционально насыщенных интернет-приложений. Однако при определенных обстоятельствах для специализированных приложений могут понадобиться внешние JavaScript-библиотеки. В этом случае можно добавить библиотеку к приложению с помощью стандартного для HTML способа – дополнительного тега <script>, однако это чревато снижением производительности приложения. К счастью, Dojo предоставляет альтернативу этому способу – dojo.io.script.

В этой статье рассматриваются преимущества и недостатки использования dojo.io.script. Приведенный пример исходного кода демонстрирует, как избежать наиболее опасных ловушек. Используемый в статье исходный код можно загрузить по данной ссылке.

Два метода загрузки внешних JavaScript-библиотек

В таблице 1 сравниваются два метода загрузки внешних JavaScript-библиотек.

Таблица 1. Тег <script> и dojo.io.script
Тег <script>dojo.io.script
Влияние на скорость загрузки страницПотенциально значительное; загрузка библиотеки блокирует начало работы страницы.Отсутствует; библиотека загружается по требованию.
Влияние на скорость выполнения кодаОтсутствует.При первоначальном использовании будет задержка на время загрузки библиотеки.
Уровень сложностиПростой. Весь код может использовать библиотеку немедленно.Сложный. Код должен грамотно отправить запрос и ждать окончания загрузки библиотеки.

Метод dojo.io.script обеспечивает явные преимущества приложениям, использующим внешнюю библиотеку только в отдельном ответвлении кода. Особенно выгодна отложенная загрузка. Метод с использованием тега <script> имеет серьезное преимущество, заключающееся в простоте использования библиотеки в приложении. Имеет смысл рассмотреть использование dojo.io.script, поскольку он при любых обстоятельствах обеспечивает лучшую скорость загрузки страниц.


Использование dojo.io.script

В листинге 1 приведен простой пример использования dojo.io.script для асинхронной загрузки одной библиотеки.

Листинг 1. Одиночный вызов dojo.io.script
dojo.require("dojo.io.script");

dojo.addOnLoad(function() {
    // Загрузить библиотеку.
    // dojo.io.script.get является асинхронным, возвращается объект dojo.Deferred
    var deferred = dojo.io.script.get({url : "url_of_library.js"});

    // Обработка отложенного обратного вызова
    deferred.then(function() {
        // Эта функция вызывается, когда библиотека успешно загружается
        // Здесь необходимо вставить код приложения, зависящий от библиотеки
    }, function() {
        // Эта функция вызывается при возникновении ошибки
    });
});

Расширенное использование

В случае использования библиотек, имеющих несколько модулей с межмодульными зависимостями, для достижения нужного поведения при загрузке могут понадобиться последовательные вызовы, аналогичные приведенным выше. В листинге 2 показан более сложный пример с последовательными вызовами.

Листинг 2. Последовательные вызовы dojo.io.script
dojo.require("dojo.io.script");

dojo.addOnLoad(function() {
    // Загрузка JavaScript-библиотеки, состоящей из двух модулей
    // Мы создаем частичную функцию загрузки второго модуля; 
    // Это упрощает 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"}));
    
    // Отложенная обработка выполняется здесь 
});

Управление сложностью

При загрузке мультимодульных библиотек с использованием dojo.io.script или при использовании библиотек в нескольких местах исходного кода управление dojo.io.script и получаемыми отложенными объектами может стать сложным. Основным вопросом использования библиотеки в нескольких местах является гарантия однократной загрузки модуля.

При загрузке мультимодульных библиотек или при использовании библиотеки в нескольких местах рассмотрите возможность применения промежуточных методов.


libproxy

Метод libproxy управляет межмодульными зависимостями и гарантирует однократную загрузку этих модулей. Пример использования libproxy приведен в листинге 3.

Листинг 3. Использование libproxy (libproxy_example.html)
dojo.require("proxy.jsv");

dojo.addOnLoad(function() {
    var jsvProxy = new proxy.jsv();
    
    jsvProxy.load('json-schema-draft-01').then(function() {
        // Здесь загружается JSV-модуль проверки совместимости с draft 1.
        alert("loaded JSV draft 1");
    });
});

В листинге 4 показано, как использовать libproxy для упаковки процедуры загрузки библиотеки Гэри Курта JSON Schema Validator (JSV).

Листинг 4. Упаковка загрузки библиотеки JSV (proxy/jsv.js)
dojo.provide("proxy.jsv");

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

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

    /**
     * В этом файле мы определяем структуру нашей библиотеки
     * и ее межмодульные зависимости
     */
    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'] 
            }
        };
    }
    
});

В листинге 5 показан исходный код libproxy.

Листинг 5. Базовая реализация для упаковки библиотеки (com/ibm/developerworks/libproxy.js)
dojo.provide("com.ibm.developerworks.libproxy");

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

/**
 * Не используйте этот класс напрямую; расширьте его
 * и переопределите поле modules в конструкторе
 */
dojo.declare("com.ibm.developerworks.libproxy", [], {

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

    /**
     * Хранит модули библиотеки (и ссылки на их зависимости,
     * если они есть).
     * 
     * NB: массивы 'sources' и 'deps' будут загружаться одновременно.
     * Если нужно сериализировать этот процесс, добавьте еще один уровень модулей,
     * т.е. uri.js ДОЛЖЕН быть загружен до jsv.js
     * 
     * Массив 'sources' содержит объекты, передаваемые в полном объеме
     * в dojo.io.script.get()
     * 
     * Пример, { 'module1Ref': { sources: [{ url: "module1.js" }] },
     * 'module2Ref': { sources: [{ url: "module2.js" }], deps: ['module1'] } };
     */
    modules : null,

    /**
     * Возвращает объект dojo.Deferred, методы callback/errback которого
     * активизируются по готовности модуля к использованию.
     * Последовательность обратных вызовов будет содержать ссылку на модуль.
     * 
     * Пример использования: load('module2').then(function() {});
     */
    load : function(/* String */moduleRef) {
        var F = this.declaredClass + ".";
        console.debug(F + "load()", arguments);

        // Проверка кэша - загружался ли этот модуль библиотеки ранее?
        if (this._moduleDeferreds[moduleRef]) {
            return this._moduleDeferreds[moduleRef];
        }

        // Создать новый deferred и поместить в кэш
        var deferred = this._moduleDeferreds[moduleRef] = new dojo.Deferred();

        var module = this.modules[moduleRef];
        if (module) {
            deferred.callback(moduleRef);
            if (module.deps) {
                // Параллельно загрузить зависимости
                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));
            }
            // Параллельно загрузить исходники
            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;
    }
});

Заключение

Длительная загрузка страниц при использовании нескольких инструментальных JavaScript-пакетов может быстро превратиться в проблему. В статье рассматривался подход, альтернативный подходу с использованием тегов <script>. Для ускорения времени загрузки страниц можно использовать функциональность dojo.io.script, загружая библиотеки "отложенным" способом. Для упрощения реализации этого подхода можно использовать libproxy в качестве промежуточного уровня, управляющего зависимостями и загрузкой.


Загрузка

ОписаниеИмяРазмер
Пример, упаковка JSV-библиотеки с помощью libproxysample.zip4 КБ

Ресурсы

Научиться

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Web-архитектура, SOA и web-сервисы
ArticleID=822354
ArticleTitle=Загрузка внешних JavaScript-библиотек по требованию с помощью Dojo 1.5
publish-date=06212012