Статьи

Простая загрузка скриптов с помощью yepnope.js

Официально выпущенный Алексом Секстоном и Ральфом Хольцманном в конце февраля 2011 года, загрузчик ресурсов yepnope.js поддерживает асинхронную, условную загрузку и предварительную загрузку ресурсов JavaScript и CSS. Это делает управление зависимым условным кодом быстрым.

Переизданный учебник

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

Этот изящный загрузчик ресурсов, размер которого составляет всего 1,6 КБ, упакован с помощью Modernizer и отлично подходит для загрузки полизаполнений, предварительной загрузки или «заполнения» кэша пользователей или в качестве простого асинхронного загрузчика / фильтра ресурсов!

Для тех из вас, кто не знаком с полифиллами, они, по сути, являются плагинами или оболочками, которые позволяют использовать новые или будущие технологии в старых браузерах, например, базы данных Web SQL, преобразования CSS3 и т. Д.

Yepnope теперь также поддерживает ряд префиксов и фильтров, которые при добавлении к URL-адресу ресурса добавляют еще один уровень тонкой настройки или настройки к его основной функциональности. Как будто это не было уже хорошо, yepnope также предоставляет вам механизм для определения ваших собственных префиксов и фильтров. Давайте посмотрим, что может сделать yepnope.js!


YepNope

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

Асинхронные загрузчики удаляют присущий скрипту характер блокировки.

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

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

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

Асинхронная загрузка не обходится без предостережений. Когда сценарии загружаются традиционным способом, встроенный код не анализируется и не выполняется до тех пор, пока внешние сценарии не будут полностью загружены последовательно. Это не относится к асинхронной загрузке. Фактически, встроенные сценарии обычно анализируются / выполняются, пока сценарии все еще загружаются. Аналогичным образом браузер также загружает ресурсы и отображает страницу во время загрузки сценариев. Таким образом, мы можем прийти к ситуациям, когда встроенный код, который, возможно, зависит от загружаемого скрипта / библиотеки, выполняется до того, как его зависимость готова или до / после того, как сам DOM готов. Таким образом, большинство загрузчиков сохраняют порядок, в котором выполняются сценарии, обеспечивая обратный вызов, когда сценарий загружен и готов. Это позволяет нам запускать любой зависимый встроенный код в качестве обратного вызова, возможно, в оболочке, готовой к DOM, где это применимо.

Кроме того, при работе с небольшой или хорошо оптимизированной страницей DOM может быть на самом деле готов или даже загружен до завершения загрузки самих скриптов! Таким образом, если рассматриваемая страница не улучшается постепенно, так как она в значительной степени опирается на JavaScript для стилизации, возможно, имеется FOUC или флеш из не стилизованного контента. Точно так же пользователи могут даже испытать краткий FUBC или вспышку несоответствующего содержания. Важно помнить об этом всякий раз, когда вы используете загрузчик скриптов / ресурсов.


Тестовый объект yepnope имеет семь основных свойств, любое из которых является необязательным. Этот объект включает реальный тест, ресурсы, которые будут загружены в результате теста, ресурсы, которые будут загружены независимо от теста, а также обратные вызовы. Вот взгляд на реквизиты тестового объекта yepnope:

  • Логическое значение, представляющее условие, которое мы хотим проверить.

  • Строка или массив / объект строк, представляющих URL ресурсов для загрузки, если тест верен .

  • Строка или массив / объект строк, представляющих URL ресурсов для загрузки, если тест ложный .

  • Строка или массив / объект строк, представляющих URL ресурсов для загрузки независимо от результата теста.

  • Строка или массив / объект строк, представляющих URL ресурсов для загрузки независимо от результата теста. Это, в основном, синтаксический сахар, так как его функция, как правило, такая же, как функция load .

  • Функция, которая будет вызываться для каждого ресурса при его последовательной загрузке.

  • Функция, которая будет вызвана один раз, когда все ресурсы будут загружены.

Теперь, чтобы получить представление о синтаксисе, давайте рассмотрим простейшее использование yepnope: загрузка одного ресурса.

1
yepnope(‘resources/someScript.js’);

… или, возможно, загрузка массива ресурсов.

1
2
3
4
yepnope([
    ‘resources/someScript.js’,
    ‘resources/someStyleSheet.css’
]);

Как насчет литерала объекта, чтобы мы могли использовать именованные обратные вызовы позже?

1
2
3
4
yepnope({
    ‘someScript’ : ‘resources/someScript.js’,
    ‘someStyleSheet’ : ‘resources/someStyleSheet.css’
});

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


Итак, мы можем загружать ресурсы асинхронно! Это здорово, но что, если некоторым страницам не требуется определенный ресурс? Или что делать, если ресурс нужен только в конкретном браузере, который не поддерживает новейшие технологии?

Нет проблем! Это где основная цель Yepnope становится в центре внимания. Используя свойство test, мы можем условно загружать ресурсы в зависимости от необходимости. Например, предположим, что библиотека Modernizer загружена.

Для тех из вас, кто не знаком с Modernizer, это отличный набор тестов, используемый для обнаружения поддержки функций HTML5 и CSS3 в браузерах.

Modernizer добавляет соответствующие js flexbox no-canvas элемент html страниц, представляющий поддерживаемые и не поддерживаемые функции, например, « js flexbox no-canvas » и т. Д. Кроме того, вы можете получить доступ к каждому из тестов Modernizer, которые возвращают логические значения по отдельности в вашем коде.

Итак, используя Modernizer, давайте hashchange поддержку событий hashchange а также поддержку истории сеансов!

1
2
3
yepnope({
    test : Modernizr.hashchange && Modernizr.history
});

Этот тест, конечно, вернет true только если браузер поддерживает обе эти функции.


С нашим набором условий теста мы теперь определим, какие ресурсы загружать, основываясь на результатах этого теста. Другими словами, если вам нужно загрузить определенный ресурс только в том случае, если в браузере отсутствует функция или если тест не пройден, вы можете просто определить этот ресурс в предложении nope . И наоборот, вы можете загружать ресурсы при прохождении теста внутри предложения yep .

Итак, предполагая, что браузер не поддерживает одну из этих двух функций, мы загрузим плагин jQuery Бена Алмана , который обеспечивает поддержку hashchange и истории в старых браузерах, которые не поддерживают ни одну из этих функций.

1
2
3
4
yepnope({
    test : Modernizr.hashchange && Modernizr.history,
    nope : ‘resources/jquery.ba-hashchange.js’
});

В приведенном выше примере мы не будем использовать свойство yep как мы предоставляем шим только в случае необходимости.

Чтобы проиллюстрировать предложение yep, давайте проверим поддержку преобразования CSS3, а затем загрузим таблицу стилей для браузеров, которые поддерживают преобразования, и простую таблицу стилей для браузеров, которые этого не делают. Кроме того, мы загрузим плагин jQuery, который также имитирует преобразования CSS3.

1
2
3
4
5
yepnope({
    test : Modernizr.csstransforms,
    yep : ‘resources/cssTransform.css’
    nope : [‘resources/noTransform.css’, ‘jQuery.pseudoTransforms.js’]
});

Обратите внимание, что оба этих примера будут загружать все ресурсы асинхронно, так как остальная часть страницы загружается и отображается!


Yepnope также предоставляет способ загрузки ресурсов независимо от результатов теста с помощью свойства load . Функция load всегда будет загружать любой ресурс, на который она подается, независимо от результата test . Точно так же both пропеллера, которые, по сути, являются просто синтаксическим сахаром, также загружают ресурсы независимо от результата теста или, более точно, на любом из результатов.

1
2
3
4
5
yepnope({
    test : Modernizr.hashchange && Modernizr.history,
    nope : ‘resources/jquery.ba-hashchange.js’,
    load : ‘resources/somethingWhichIsAlwaysLoaded.css’,
});

1
2
3
4
5
yepnope({
    test : Modernizr.hashchange && Modernizr.history,
    nope : ‘resources/jquery.ba-hashchange.js’,
    both : ‘resources/somethingWhichIsAlwaysLoaded.css’,
});

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


Как упоминалось ранее, мы не можем писать встроенный код обычным способом, если этот код зависит от одного из загружаемых скриптов. Таким образом, мы будем использовать функцию обратного вызова yepnope, которая запускается один раз для каждого ресурса после завершения загрузки. Функция обратного вызова принимает три параметра, которым назначаются следующие:

  • Эта строка представляет URL ресурса, который был загружен

  • Логическое значение, представляющее статус загрузки.

  • Если используется массив или объект ресурсов, это будет представлять индекс или имя свойства файла, который был загружен

Давайте рассмотрим простой обратный вызов на примере плагина hashchange из предыдущего. Мы будем использовать метод привязки jQuery для привязки обработчика к событию hashchange window :

01
02
03
04
05
06
07
08
09
10
11
12
13
yepnope({
    test : Modernizr.hashchange && Modernizr.history,
    nope : ‘resources/jquery.ba-hashchange.js’,
    callback : function(url, result, key){
     
        $(function(){
            $(window).bind(‘hashchange’, function(){
                console.info(location.hash);
            });
        });
     
    },
});

Независимо от того, в каком состоянии находится DOM, этот обратный вызов, который в данном конкретном случае находится в оболочке с готовым документом, сработает, как только будет загружен ресурс.

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

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

Давайте рассмотрим пример, в котором мы загружаем jQuery, а также плагин jQuery hashchange, который зависит от того, загружается ли сначала jQuery. Однако на этот раз мы будем использовать объектные литералы!

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
yepnope({
    test : Modernizr.hashchange && Modernizr.history,
    nope : {
        ‘jquery’ : ‘resources/jquery-1.5.1.min.js’,
        ‘hashch’ : ‘resources/jquery.ba-hashchange.js’
    },
    callback : {
        ‘jquery’ : function(url, result, key){
            console.info(‘I will fire only when the jquery script is loaded’);
        },
        ‘hashch’ : function(url, result, key){
            console.info(‘I will fire only when the hashchange script is loaded’);
             
            // This code will be added to jQuerys DOM ready call stack
            $(function(){
                $(window).bind(‘hashchange’, function(){
                    console.info(location.hash);
                });
            });
        }
    }
});

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


Наконец, у нас есть complete обратный вызов, который вызывается только один раз, после того как все ресурсы закончили загрузку. Так, например, если вы «загружаете» веб-приложение, и код, который вам нужно запустить, зависит от всех загружаемых файлов, а не указывает callback для каждого ресурса, вы должны написать свой код в complete обратный вызов, так что он запускается только один раз, после загрузки всех его зависимостей. В отличие от функции callback , complete не принимает никаких параметров и не имеет доступа к url , result или key .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
yepnope({
    test : Modernizr.hashchange && Modernizr.history,
    nope : [
        ‘resources/jquery-1.5.1.min.js’,
        ‘resources/jquery.ba-hashchange.js’
    ],
    complete : function(){
     
        console.info(‘I will fire only once when both jquery and the hashchange script are loaded’);
         
        // This code will be added to jQuerys DOM ready call stack
        $(function(){
            $(window).bind(‘hashchange’, function(){
                console.info(location.hash);
            });
        });
     
    }
});

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


Yepnope также предоставляет нам еще одну изящную маленькую особенность: префиксы и фильтры! Префиксы по умолчанию, предоставляемые yepnope, которые всегда добавляются к началу URL ресурса, используются для определения файла как CSS, предварительной загрузки ресурса или ориентации на Internet Explorer или одну из его версий соответственно. Давайте посмотрим:

  • Этот префикс используется для того, чтобы заставить yepnope рассматривать ресурс как таблицу стилей. По умолчанию yepnope рассматривает файлы .css как таблицы стилей, а все остальное — как файл JavaScript. Так что, если вы обслуживаете CSS динамически, этот префикс заставит yepnope рассматривать этот ресурс как таблицу стилей.

    1
    yepnope(‘css!styles.php?colorscheme=blue’);

  • Этот префикс позволяет загружать / кэшировать ресурс, не выполняя его.

    1
    yepnope(‘preload!userInterface.js’);

  • Могут возникнуть ситуации, когда вам нужно загружать определенные ресурсы, только если вы работаете с Internet Explorer или определенной версией Internet Explorer. Таким образом, префиксы ie помогают вам ориентировать загрузку ресурсов на ie или конкретные его версии. Вот список поддерживаемых префиксов ie где gt обозначает «версии больше чем», а lt обозначает «версии меньше чем».

    • Internet Explorer:
      ie!
    • Internet Explorer по номеру версии:
      ie5! , ie6! , ie7! , ie8! , ie9!
    • Версии Internet Explorer больше чем:
      iegt5! , iegt6! , iegt7! , iegt8!
    • Версии Internet Explorer меньше чем:
      ielt7! , ielt8! , ielt9!

    Все эти фильтры являются цепочечными и служат своего рода оператором OR в том случае, если один из них оценивается как true ресурс будет загружен. Итак, если нам нужно настроить таргетинг на ie7 и ie8, мы просто добавим соответствующие фильтры к URL-адресу ресурса следующим образом:

    1
    yepnope(‘ie7!ie8!userInterface.js’);

Если вам когда-либо понадобится, yepnope также предоставляет средства для создания ваших собственных фильтров и префиксов с помощью методов addFilter и addPrefix . Любому созданному вами фильтру или префиксу передается resourceObject содержащий ряд полезных реквизитов. Помните, однако, чтобы вернуть resourceObject поскольку yepnope требует, чтобы вы это сделали. Вот посмотрите на resourceObject :

  • URL загружаемого ресурса.

  • Массив примененных префиксов.

  • Обратный вызов, который запускается после загрузки каждого скрипта, отдельно от других.

  • Логическое значение, которое вызывает предварительную загрузку без выполнения.

  • Расширенная функция, которая принимает те же параметры, что и загрузчик.

  • Логическое значение, которое заставляет ресурс обрабатываться как javascript.

  • Логическое значение, которое заставляет ресурс обрабатываться как таблица стилей.

  • Логическое значение, определяющее, загружать или нет текущий ресурс.

Допустим, например, что вам нужна возможность переключать загрузку ресурсов между вашим CDN и веб-сервером на лету. Можем ли мы сделать это, хотя !? Ага! Давайте создадим два префикса, один для загрузки с CDN, а другой для загрузки с вашего веб-сервера.

01
02
03
04
05
06
07
08
09
10
11
12
13
yepnope.addPrefix(‘local’, function(resourceObj) {
 
    resourceObj.url = ‘http://mySite/resources/’ + resourceObj.url;
    return resourceObj;
     
});
     
yepnope.addPrefix(‘amazon’, function(resourceObj) {
 
    resourceObj.url = ‘http://pseudoRepository.s3.amazonaws.com/’ + resourceObj.url;
    return resourceObj;
     
});

1
2
3
4
yepnope([
    ‘local!css/typography.css’,
    ‘amazon!defaultStyle.css’
]);


Таким образом, сохраняя очень малую площадь, условный загрузчик yepnope обладает множеством полезных функций! Есть, однако, несколько вещей, которые вы должны знать, прежде чем использовать его.

  • Как и в случае любого асинхронного загрузчика, вы не можете использовать document.write .

  • Версии Internet Explorer менее девяти не гарантируют, что обратные вызовы запускаются сразу после запуска соответствующего сценария.

  • Ваш скрипт может быть загружен и выполнен до того, как DOM будет готов. Итак, если вы манипулируете DOM, желательно использовать готовую оболочку DOM.

  • То, что вы используете асинхронный загрузчик, не означает, что вам не следует объединять свои ресурсы там, где это возможно.

  • Более старые версии Internet Explorer могут загружать только два ресурса из одного домена одновременно, тогда как другие версии могут загружать до шести. Итак, если вы загружаете несколько файлов, рассмотрите возможность использования поддоменов или CDN.


В общем, я нашел yepnope отличной утилитой! Он не только поддерживает асинхронную загрузку как скриптов, так и таблиц стилей, но также предоставляет хороший, чистый способ условной загрузки полифайлов HTML5 и CSS3. Механизм обратного вызова хорошо продуман, а возможность добавлять свои собственные префиксы и фильтры просто великолепна! С точки зрения производительности я обнаружил, что yepnope несколько схожи с другими загрузчиками, такими как LABjs Getify Solutions и require.js Джеймса Бёрка . Очевидно, что каждый загрузчик индивидуален и подходит для разных нужд, но если вы еще этого не сделали, я призываю вас попробовать yepnope.js !