Загрузка по требованию и jQuery

    Несмотря на то, что необходимо минимизировать количество http-запросов, иногда (или часто, в зависимости от задачи) бывает полезно загружать часть «тяжелого» функционала только тогда, когда он действительно понадобится на странице.
    У jQuery есть механизм, позволяющий осуществить это — $.getScript, однако, он обладает рядом недостатков:
    • не запоминаются уже загруженные или загружаемые в данный момент скрипты, при повторном запросе опять идет их загрузка.
    • нельзя указать сразу несколько скриптов
    • выключен кэш (к каждому урлу насильно приписываются параметры типа ?_=1242843920520). Зачем это было так жестко сделано, для меня осталось загадкой.
    • у коллбэка нельзя задать контекст (это вообще болезнь коллбэков jQuery).
    Пришлось написать небольшой плагин, лишенный вышеперечисленных недостатков:

    $.requireScript(url, callback, [context], [options])
    Где:
    url — урл загружаемого скрипта (может быть массивом урлов)
    callback — коллбэк-функция, вызываемая после загрузки скриптов
    context — контекст, в котором вызывается коллбэк-функция (опционален)
    options — параметры; в данный момент поддерживается только один параметр — parallel, указывающий, нужно ли использовать параллельную загрузку для нескольких скриптов (по умолчанию — true)


    Может кому-то пригодится. Скачать и попробовать можно с code.google.

    UPDATE: согласно замечаниям в комментах, $.loadScript переименован в $.requireScript, и теперь можно указать несколько урлов сразу.
    Share post

    Comments 52

      +3
      Огромное спасибо, у меня как раз встала проблема повторной загрузки.
      С удовольствием буду использовать!
      А вы собираетесь отписать в jQuery о включении этого чуда стандартную поставку?
        +3
        Попробую
        0
        Спасибо большущее! вещь очень полезная
          0
          Полезная штука, пригодится ;)
            0
            сам jQuery настолько «тяжелый», что оптимизировать последующую загрузку странно.

            Однако встречаются и случаи, когда jQuery + пара плагинов навернуто на mootools + пара плагинов. Создателей таких сайтов вообще отстреливать надо…
              0
              Что странного в том, чтобы подгружать, допустим, 100 Кб какого-нибудь функционала только тогда, когда он действительно понадобится на странице (учитывая, что он может и не понадобится)?
                0
                да ничего. Просто если для того, чтобы загрузить 100Кб по требованию, нужно выгрузить на каждую страницу 50Кб jQuery, — это, имхо, перебор.
                  0
                  Обычно, jQuery все-таки нужен не для того чтобы загрузить 100Кб по требованию. Здесь предлагается решение, когда jQuery уже используется на проекте, но есть необходимость в ленивой загрузке части функционала.
                    –4
                    Это понятно. Но лично я считаю использование всего jQuery признаком ленивости программистов. Да, это средство для быстрой разработки. Да, это экономит силы. Но если проект по размеру выходит за рамки размера самого jQuery, то его точно нужно рефакторить и выбрасывать лишнее.
                      +3
                      Не понял, если js проекта по размеру больше, чем размер jQuery, то его (jQuery) нужно рефакторить и выбрасывать все лишнее? Мне кажется это более чем странно. Как мне думается, чем больше проект, тем наоборот, все больше и больше бонусов начинаешь получать от использования jQuery.

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

                        Я просто к тому, что, например, CSS-селекторы в самом jQuery за счет оберток работают в 3 раза медленнее, чем в Sizzle (про YASS я молчу).
                        Сам Resig неоднократно писал, что рефакторил и будет рефакторить код на предмет производительности. Но код-то от этого меньше не становится. Вот если бы выложил модульную структуру, чтобы скачать только необходимое — респект ему и хвала.

                        Просто использование какой-то «чужой» библиотеки в большом проекте обычно приводит к тому, что издержки от ее применения и работы становятся больше, чем выигрыш — приходится писать громоздкие конструкции и опираться на определенную, часто избыточную, логику библиотеки.
                          +1
                          Одна из причин перехода на новые версии, как вы сами заметили, — это увеличение производительности в новых версиях. Другая — то, что там обычно появляется новых функционал (обычно востребованный). А можно увидеть где-нибудь тесты, где Sizzle оказывается быстрее в 3 раза чем он же, обернутый jQuery? Да и вообще мне кажется, что если в вашем приложении критична скорость селекторов, то надо подумать об оптимизации использования селекторов, а не увеличения их производительности.
                            +1
                            боюсь, что все мои последующие комментарии так же будут заминусованы офисным планктоном, но
                            ajaxian.com/archives/sizzle-john-resig-has-a-new-selector-engine
                            sizzlejs.com/
                            yass.webo.in/slickspeed/?yass_0-3-8/Peppy_0-1-2/Sizzle_20-05-09/jQuery_1-3-2

                            P.S. да, обертки jQuery уже не так сильно нагружают Sizzle (или частично переехали в Sizzle?), поэтому разницы в скорости нет.
                            P.P.S. стоит учитывать, что в Peppy/YASS включено кэширование, поэтому результаты отличаются на порядок. Однако даже с выключенным кэшированием все равно значительный прирост скорости.
                              0
                              Хм. Интересно про YASS, не знал о нём ничего до сих пор.
                              Я насколько знаю jresig свои библиотеки делает что бы они и xml обрабатывали. YASS это не делает?
                                0
                                YASS работает с DOM-деревом. Без разницы, в каком документе
                                  0
                                  Почему на странице с тестированием нет cssquery? jresig в книге пишет что когда он начал jquery, то хотел повторить именно функционал cssquery только по-своему.
                                    0
                                    добавил, но, имхо, не надо ворошить прошлое: слишком уж оно медленное было :)
                                    0
                                    Ещё два вопроса.
                                    Если yass будет работать несколько секунд, он блокирует интерфейс браузера?
                                      +1
                                      любая библиотека будет блокировать интерфейс браузера. Это настраивается уже кодом более высокого уровня (SetTimeout, например — Lecompte об этом писал, а я переводил и в книжку включал).

                                      YASS можно разобрать и собрать свое решение.
                                      Весь код подробно документирован (на 10Кб кода 15Кб комментариев).
                                        0
                                        Хорошо, я посмотрю код.
                                        Переводы читал, но похоже я ещё не understending про блокировку до конца. :)
                                      0
                                      В yass используется общий код который один на все браузеры или есть оптимизированный код под конкретные браузеры?
                                      Так делают программисты под windows mobile, для разных процессоров и инструкций в одной программе пишут несколько функций оптимизированные под разные процессоры.
                                        0
                                        есть некоторые оптимизированные конструкции. Но тут палка о двух концах: мы не можем проверять на каждый чих, какой у нас браузер (пусть даже это будет закэшированная переменная): издержки на проверки слишком большие будут по сравнению с выигрышом. Да и код существенно увеличится.
                            0
                            Ну, ведь вмешательство в фреймворк на некотором этапе — это плохо относительно общей концепции фреймворка.
                              0
                              Пользователь — всегда прав. И именно он приносит деньги. А уж как удовлетворить пользователя — это этом нужно думать ДО начала использования фреймворка, а не после, когда уже тяжело что-то менять, да и неверное идеологически.
                                0
                                К сожалению, постановка денег во главу угла приводит к искажению концепций и «заплатничеству», ИМХО.
                                  0
                                  интересно, а что же должно быть во главе угла, если мы делаем коммерческий продукт?
                                    0
                                    я не говорю, что там должно быть что-то другое, но сам факт приводит к вышеназванному.
                              0
                              Проекты бывают разные. jQuery может сильно упростить жизнь в некоторых случаях
                                0
                                я это и написал почти в самом первом комментарии. Просто, имхо, очень часто jQuery используют везде, где можно и где нельзя. Это не есть гуд. jQuery — не всесильное веб-приложение. Просто чоередная, очень хорошая и правильная, но очередная Javascript-библиотека
                        +1
                        19kb это не тяжелый. Это фигня.

                        А на специальных сайтах бывают и сотни килобайт JS. И их разумно подгружать по необходимости.
                          0
                          :) давайте, мы будем говорить о конкретных цифрах?
                          Если у вас 19Кб минимизированного и gzip-сжатого JS кода в jQuery, то у вас дополнительного функционала никак не будет «сотни килобайт».
                          Если имеется в виду несжатого функционала на сотни килобайт, то и про jQuery стоит упомянуть в соответствующем ключе.

                          Я про относительные размеры библиотек, а не про абсолютные. Сейчас понятие «абсолютной тяжести» скриптов несколько размыто в связи с большим разнообразием каналов связи у конечных пользователей.
                            0
                            При разработке сложных внутренних интерфейсов интранет-систем даже сжатого и минимизированного JS может быть сильно больше 100k.

                            Не за счет собственного кода, конечно, а просто потому, что легко и эффективно использовать тяжелые внешние библиотеки. Тот же jquery ui и аналоги.
                              0
                              Знаю проект, в котором 2 мегабайта несжатого прикладного JS кода. ;-) После yuicompressor остается порядка 400К. Предлагаете загружать его сразу?)
                                +1
                                я это где-то говорил?

                                И данное исключение только подтверждает правило — сколько таких проектов по миру? Они используют jQuery? Естественно, что речь пойдет о модульной загрузке, но jQuery тут явно проигрывает тому же Yahoo!..
                          0
                          «к каждому урлу насильно приписываются параметры типа ?_=1242843920520»

                          это что бы из кэша скрипт не вынимало а брало последнюю версию. просто принудительно так делается. урл+timestamp
                            0
                            Я понимаю как это работает, я не понимаю зачем это так сделано. Это должно быть как минимум опциональным, иначе каждый раз одно и тоже будет скачиваться. И чаще на продакшене все-таки должно одно и тоже отдаваться.
                              0
                              Вернее, на продакшене не должно скачиваться одно и тоже, а должно браться из браузерного кэша.
                                0
                                Я понял. Ну что я могу сказать… костыли-подпорки чьи-то
                            0
                            Пожелания:

                            1)
                            Лучше бы использовали концепцию $.usescript. Всего лишь смена имени.

                            2)
                            Чаще всего нужно выполнить $.usescript(['first-one', 'second-one'], function()
                            {
                            //…
                            });

                            3)
                            Хочу задавать $.expand($.usescript.defaults, { prefix: '/js/', suffix: '.js' });

                            4)
                            Скрипт может по уму пропарсить DOM, чтобы знать, какие скрипты уже включены в страницу.
                              0
                              Спасибо, буду думать. Мне кажется только пункт 3 немного лишний. Лучше в своем приложении сделать какой-нибудь NAMESPACE.useModule(), где уже будет прописано откуда и что брать. А $.loadScript все-таки ф-ия немного более низкого уровня.
                                0
                                Это свего лишь умолчания. В обьекте опций можно передать другие переменные.

                                Кстати, соответственно context должен быть удален, вместо него передавать options, у которых вероятно свойство scope (то есть context, но scope более привычен, такое именование принято, например, в Ext.JS).
                                  0
                                  Вообщем, пока только переименовал $.loadScript в $.useScript и сделал поддержку массива урлов. Остальное под вопросом.
                                    0
                                    $(document).ready(function()
                                    {
                                    $('script[src]').each(function()
                                    {
                                    save its this.src in table of already loaded scripts…
                                    });
                                    });
                                      0
                                      вернее, $(this).attr('src'), чтобы пути корректно брать, без приколов браузеров.
                                        0
                                        Не нравится $('script[src]') — проход по всему дереву. Да и не дает этот метод гарантии — допустим, в подключаемом в head скрипте 1.js стоит вызов $.useScript('2.js') напрямую и после этого в head идет подключение 2.js. В итоге, все равно 2 запроса за одним и тем же уйдет.
                                        Надо еще покопать и подумать в этом направлении.
                                          0
                                          тогда надо дать право на
                                          $.usescript.registerLoaded('scriptName');
                                            0
                                            и в форме

                                            $.usescript.registerLoaded(['scriptName', [scriptName]);

                                            А там уже сам пользователь пусть решает…

                                            P.S.: А с каких пор прохождение по DOM по тэгу стало дорогим?)
                                              0
                                              добавил $.useScript.registerLoaded

                                              Не то чтобы прохождение по тэгу сильно дорого, но как-то оно смущает. Тем более ничего конкретно оно не дает. Потому что на продакшене основной функционал пакуется в один файл, и ссылаться по имени начального js там будет сложно. Лучше уж registerLoaded.
                                0
                                Осталось выложить в plugins.jquery.com/
                                +1
                                Существует xLazyLoader, который собираются интегрировать в jQuery Core.
                                  0
                                  Ага, надо мне почаще смотреть их roadmap'ы :)

                                Only users with full accounts can post comments. Log in, please.