Динамически загружать файл JavaScript - PullRequest
151 голосов
/ 22 августа 2008

Как вы можете надежно и динамически загрузить файл JavaScript? Это можно использовать для реализации модуля или компонента, который при «инициализации» будет динамически загружать все необходимые скрипты библиотеки JavaScript по требованию.

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

Как основные библиотеки JavaScript достигают этого (Prototype, jQuery и т. Д.)? Объединяют ли эти инструменты несколько файлов JavaScript в одну распространяемую версию файла сценария для сборки? Или они динамически загружают вспомогательные «библиотечные» скрипты?

Дополнение к этому вопросу: есть ли способ обработки события после загрузки динамически включенного файла JavaScript? Прототип имеет document.observe для событий всего документа. Пример:

document.observe("dom:loaded", function() {
  // initially hide all containers for tab content
  $$('div.tabcontent').invoke('hide');
});

Какие события доступны для элемента скрипта?

Ответы [ 24 ]

1 голос
/ 14 февраля 2012

Существуют сценарии, разработанные специально для этой цели.

yepnope.js встроен в Modernizr, а lab.js - более оптимизированная (но менее удобная для пользователя версия.

Я бы не советовал делать это через большую библиотеку, такую ​​как jquery или прототип - потому что одно из главных преимуществ загрузчика скриптов - это возможность загружать скрипты рано - вам не нужно ждать, пока jquery и все ваши доменные элементы загружаются перед запуском проверки, чтобы увидеть, хотите ли вы динамически загрузить скрипт.

0 голосов
/ 18 апреля 2018

Как то так ...

<script>
     $(document).ready(function() {
          $('body').append('<script src="https://maps.googleapis.com/maps/api/js?key=KEY&libraries=places&callback=getCurrentPickupLocation" async defer><\/script>');
     });
</script>
0 голосов
/ 03 августа 2017

Я знаю, что мой ответ немного запоздал на этот вопрос, но вот отличная статья в www.html5rocks.com - Глубокое погружение в мутные воды загрузки скриптов .

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

Учитывая, что у вас есть четыре сценария с именем script1.js, script2.js, script3.js, script4.js, вы можете сделать это с помощью , применяя async = false :

[
  'script1.js',
  'script2.js',
  'script3.js',
  'script4.js'
].forEach(function(src) {
  var script = document.createElement('script');
  script.src = src;
  script.async = false;
  document.head.appendChild(script);
});

Теперь Спецификация говорит: : Скачивайте вместе, выполняйте по порядку, как только загрузите все.

Firefox <3.6, Opera говорит: </strong> Я понятия не имею, что это за «асинхронная» вещь, но так получается, что я выполняю сценарии, добавленные через JS, в порядке их добавления.

Safari 5.0 говорит: Я понимаю «асинхронный», но не понимаю, как установить для него «ложный» с JS. Я выполню ваши сценарии, как только они приземлятся, в любом порядке.

IE <10 говорит: </strong> Нет понятия об «асинхронности», но есть обходной путь, использующий «onreadystatechange».

Все остальное говорит: Я твой друг, мы собираемся сделать это по книге.

Теперь полный код с IE <10: </strong>

var scripts = [
  'script1.js',
  'script2.js',
  'script3.js',
  'script4.js'
];
var src;
var script;
var pendingScripts = [];
var firstScript = document.scripts[0];

// Watch scripts load in IE
function stateChange() {
  // Execute as many scripts in order as we can
  var pendingScript;
  while (pendingScripts[0] && pendingScripts[0].readyState == 'loaded') {
    pendingScript = pendingScripts.shift();
    // avoid future loading events from this script (eg, if src changes)
    pendingScript.onreadystatechange = null;
    // can't just appendChild, old IE bug if element isn't closed
    firstScript.parentNode.insertBefore(pendingScript, firstScript);
  }
}

// loop through our script urls
while (src = scripts.shift()) {
  if ('async' in firstScript) { // modern browsers
    script = document.createElement('script');
    script.async = false;
    script.src = src;
    document.head.appendChild(script);
  }
  else if (firstScript.readyState) { // IE<10
    // create a script and add it to our todo pile
    script = document.createElement('script');
    pendingScripts.push(script);
    // listen for state changes
    script.onreadystatechange = stateChange;
    // must set src AFTER adding onreadystatechange listener
    // else we’ll miss the loaded event for cached scripts
    script.src = src;
  }
  else { // fall back to defer
    document.write('<script src="' + src + '" defer></'+'script>');
  }
}

Несколько трюков и минимизация позже, это 362 байта

!function(e,t,r){function n(){for(;d[0]&&"loaded"==d[0][f];)c=d.shift(),c[o]=!i.parentNode.insertBefore(c,i)}for(var s,a,c,d=[],i=e.scripts[0],o="onreadystatechange",f="readyState";s=r.shift();)a=e.createElement(t),"async"in i?(a.async=!1,e.head.appendChild(a)):i[f]?(d.push(a),a[o]=n):e.write("<"+t+' src="'+s+'" defer></'+t+">"),a.src=s}(document,"script",[
  "//other-domain.com/1.js",
  "2.js"
])
0 голосов
/ 22 августа 2008

все основные библиотеки javascript, такие как jscript, prototype, YUI, поддерживают загрузку файлов сценариев. Например, в YUI после загрузки ядра вы можете сделать следующее, чтобы загрузить элемент управления календаря

var loader = new YAHOO.util.YUILoader({

    require: ['calendar'], // what components?

    base: '../../build/',//where do they live?

    //filter: "DEBUG",  //use debug versions (or apply some
                        //some other filter?

    //loadOptional: true, //load all optional dependencies?

    //onSuccess is the function that YUI Loader
    //should call when all components are successfully loaded.
    onSuccess: function() {
        //Once the YUI Calendar Control and dependencies are on
        //the page, we'll verify that our target container is 
        //available in the DOM and then instantiate a default
        //calendar into it:
        YAHOO.util.Event.onAvailable("calendar_container", function() {
            var myCal = new YAHOO.widget.Calendar("mycal_id", "calendar_container");
            myCal.render();
        })
     },

    // should a failure occur, the onFailure function will be executed
    onFailure: function(o) {
        alert("error: " + YAHOO.lang.dump(o));
    }

 });

// Calculate the dependency and insert the required scripts and css resources
// into the document
loader.insert();
...