Динамично загрузите файл JavaScript

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

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

Как господствующие библиотеки JavaScript достигают этого (Прототип, jQuery, и т.д.)? Сделайте эти инструменты сливают несколько файлов JavaScript в единственный &#39 без ограничений на свободное распространение; build' версия файла сценария? Или сделайте они делают любую динамическую погрузку вспомогательного ' library' сценарии?

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

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

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

Комментарии к вопросу (1)
Решение

Вы можете написать динамические признаки сценария (использующий Прототип):

new Element("script", {src: "myBigCodeLibrary.js", type: "text/javascript"});

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

Мы часто хотим наш подчиненный кодекс по очень следующей строке и любим писать что-то как:

if (iNeedSomeMore) {
    Script.load("myBigCodeLibrary.js"); // includes code for myFancyMethod();
    myFancyMethod(); // cool, no need for callbacks!
}

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

Если Вы используете Прототип, метод Script.load похож на это:

var Script = {
    _loadedScripts: [],
    include: function(script) {
        // include script only once
        if (this._loadedScripts.include(script)) {
            return false;
        }
        // request file synchronous
        var code = new Ajax.Request(script, {
            asynchronous: false,
            method: "GET",
            evalJS: false,
            evalJSON: false
        }).transport.responseText;
        // eval code on global level
        if (Prototype.Browser.IE) {
            window.execScript(code);
        } else if (Prototype.Browser.WebKit) {
            $$("head").first().insert(Object.extend(
                new Element("script", {
                    type: "text/javascript"
                }), {
                    text: code
                }
            ));
        } else {
            window.eval(code);
        }
        // remember included script
        this._loadedScripts.push(script);
    }
};
Комментарии (4)

Нет никакого импорта / включают / требуют в JavaScript, но есть два главных способа достигнуть того, что Вы хотите:

1 - Вы можете загрузить его требованием AJAX, тогда используют оценку.

Это - самый прямой путь, но it' s ограниченный Вашей областью из-за параметров настройки безопасности JavaScript и оценкой использования открывает дверь ошибкам и хакерским проникновениям.

2 - Добавьте признак сценария с URL сценария в HTML.

Определенно лучший способ пойти. Вы можете загрузить сценарий даже от иностранного сервера и it' s убирают, поскольку Вы используете анализатор браузера, чтобы оценить кодекс. Вы можете поместить < сценарий/> признак в главе веб-страницы, или у основания тела.

Оба из этих решений обсуждены и иллюстрированы здесь.

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

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

НАПРИМЕР: my_lovely_script.js содержит MySuperObject

var js = document.createElement("script");

js.type = "text/javascript";
js.src = jsFilePath;

document.body.appendChild(js);

var s = new MySuperObject();

Error : MySuperObject is undefined

Тогда Вы перезагружаете страницу, поражающую F5. И это работает! Путание...

Таким образом, что делать с этим?

Ну, Вы можете использовать хакерское проникновение, которое автор предлагает в связи, которую я дал Вам. Таким образом, для людей второпях, он использует en событие, чтобы управлять функцией обратного вызова, когда сценарий загружен. Таким образом, Вы можете поместить весь кодекс, пользующийся отдаленной библиотекой в функции обратного вызова. НАПРИМЕР:

function loadScript(url, callback)
{
    // adding the script tag to the head as suggested before
   var head = document.getElementsByTagName('head')[0];
   var script = document.createElement('script');
   script.type = 'text/javascript';
   script.src = url;

   // then bind the event to the callback function 
   // there are several events for cross browser compatibility
   script.onreadystatechange = callback;
   script.onload = callback;

   // fire the loading
   head.appendChild(script);
}

Тогда Вы пишете кодекс, который Вы хотите использовать ПОСЛЕ ТОГО, КАК сценарий загружен в функции лямбды:

var myPrettyCode = function() {
    // here, do what ever you want
};

Тогда Вы управляете всем этим:

loadScript("my_lovely_script.js", myPrettyCode);

Хорошо, я получил его. Но it' s боль, чтобы написать весь этот материал.

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

$.getScript("my_lovely_script.js", function() {
    alert("Script loaded and executed.");
    // here you can use anything you defined in the loaded script
});
Комментарии (5)

Я использовал намного менее сложная версия недавно с jQuery:

<script src="scripts/jquery.js"></script>
<script>
  var js = ["scripts/jquery.dimensions.js", "scripts/shadedborder.js", "scripts/jqmodal.js", "scripts/main.js"];
  var $head = $("head");
  for (var i = 0; i < js.length; i++) {
    $head.append("<script src=\"" + js[i] + "\">");
  }
</script>

Это работало отлично в каждом браузере, в котором я проверил его: IE6/7, Firefox, Сафари, Opera.

Обновление: версия jQuery меньше:

<script>
  var js = ["scripts/jquery.dimensions.js", "scripts/shadedborder.js", "scripts/jqmodal.js", "scripts/main.js"];
  for (var i = 0, l = js.length; i < l; i++) {
    document.getElementsByTagName("head")[0].innerHTML += ("<script src=\"" + js[i] + "\">");
  }
</script>
Комментарии (8)

Я сделал в основном то же самое, что Вы сделали Адама, но с небольшой модификацией, чтобы удостовериться я прилагал к главному признаку, чтобы сделать работу. Я просто создал включать функцию (кодекс ниже), чтобы обращаться и со сценарием и с css файлами.

Эта функция также проверяет, чтобы удостовериться что сценарий или файл CSS hasn' t уже загруженный динамично. Это не проверяет на закодированные ценности руки и, возможно, был лучший способ сделать это, но это служило цели.

function include( url, type ){
    // First make sure it hasn't been loaded by something else.
    if( Array.contains( includedFile, url ) )
        return;

    // Determine the MIME-type
    var jsExpr = new RegExp( "js$", "i" );
    var cssExpr = new RegExp( "css$", "i" );
    if( type == null )
        if( jsExpr.test( url ) )
            type = 'text/javascript';
        else if( cssExpr.test( url ) )
            type = 'text/css';

    // Create the appropriate element.
    var tag = null;
    switch( type ){
        case 'text/javascript' :
            tag = document.createElement( 'script' );
            tag.type = type;
            tag.src = url;
            break;
        case 'text/css' :
            tag = document.createElement( 'link' );
            tag.rel = 'stylesheet';
            tag.type = type;
            tag.href = url;
            break;
    }

    // Insert it to the  and the array to ensure it is not
    // loaded again.
    document.getElementsByTagName("head")[0].appendChild( tag );
    Array.add( includedFile, url );
}
Комментарии (3)

другой потрясающий ответ

$.getScript("my_lovely_script.js", function(){

   alert("Script loaded and executed.");
  // here you can use anything you defined in the loaded script

 });

https://stackoverflow.com/a/950146/671046

Комментарии (1)

Вот является некоторый пример кода I' ve нашел..., что у кого-либо есть лучший путь?

  function include(url)
  {
    var s = document.createElement("script");
    s.setAttribute("type", "text/javascript");
    s.setAttribute("src", url);
    var nodes = document.getElementsByTagName("*");
    var node = nodes[nodes.length -1].parentNode;
    node.appendChild(s);
  }
Комментарии (1)

Если Вам уже загрузили jQuery, Вы должны использовать $ .getScript.

Это имеет преимущество перед другими ответами здесь в этом, у Вас есть построенный в функции обратного вызова (чтобы гарантировать, что сценарий загружен перед подчиненными кодовыми пробегами) и Вы можете управлять кэшированием.

Комментарии (0)

Просто узнанный о замечательной особенности в [YUI 3] [1] (во время написания доступного в выпуске предварительного просмотра). Вы можете легко вставить зависимости в библиотеки YUI и в " external" модули (что Вы ищете) без слишком большого количества кодекса: [Погрузчик YUI] [2].

Это также отвечает на Ваш второй вопрос относительно функции, вызванной, как только внешний модуль загружен.

Пример:


YUI({
    modules: {
        'simple': {
            fullpath: "http://example.com/public/js/simple.js"
        },
        'complicated': {
            fullpath: "http://example.com/public/js/complicated.js"
            requires: ['simple']  // 
Комментарии (1)

i' ve использовал еще одно решение, которое я нашел в сети..., этот находится под creativecommons, и это проверяет, был ли источник включен до вызывания функции ...

Вы можете найти файл здесь: include.js

/** include - including .js files from JS - bfults@gmail.com - 2005-02-09
 ** Code licensed under Creative Commons Attribution-ShareAlike License 
 ** http://creativecommons.org/licenses/by-sa/2.0/
 **/              
var hIncludes = null;
function include(sURI)
{   
  if (document.getElementsByTagName)
  {   
    if (!hIncludes)
    {
      hIncludes = {}; 
      var cScripts = document.getElementsByTagName("script");
      for (var i=0,len=cScripts.length; i < len; i++)
        if (cScripts[i].src) hIncludes[cScripts[i].src] = true;
    }
    if (!hIncludes[sURI])
    {
      var oNew = document.createElement("script");
      oNew.type = "text/javascript";
      oNew.src = sURI;
      hIncludes[sURI]=true;
      document.getElementsByTagName("head")[0].appendChild(oNew);
    }
  }   
} 
Комментарии (1)

у кого-либо есть лучший путь?

Я думаю, просто добавив, что сценарий к телу был бы легче тогда добавление его к последнему узлу на странице. Как насчет этого:

function include(url) {
  var s = document.createElement("script");
  s.setAttribute("type", "text/javascript");
  s.setAttribute("src", url);
  document.body.appendChild(s);
}
Комментарии (1)

Если Вы хотите СИНХРОНИЗАЦИЯ погрузка сценария, Вы должны добавить текст сценария непосредственно к признаку ГОЛОВЫ HTML. Добавление его как < сценарий src =" myscript.js" > вызовет ASYNC груз. Чтобы загрузить текст сценария от внешнего файла синхронно, используйте XHR. Ниже быстрого образца (это использует части других ответов в этом и других постов):

/*sample requires an additional method for array prototype:*/

if (Array.prototype.contains === undefined) {
Array.prototype.contains = function (obj) {
    var i = this.length;
    while (i--) { if (this[i] === obj) return true; }
    return false;
};
};

/*define object that will wrap our logic*/
var ScriptLoader = {
LoadedFiles: [],

LoadFile: function (url) {
    var self = this;
    if (this.LoadedFiles.contains(url)) return;

    var xhr = new XMLHttpRequest();
    xhr.onload = function () {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
                self.LoadedFiles.push(url);
                self.AddScript(xhr.responseText);
            } else {
                if (console) console.error(xhr.statusText);
            }
        }
    };
    xhr.open("GET", url, false);/*last parameter defines if call is async or not*/
    xhr.send(null);
},

AddScript: function (code) {
    var oNew = document.createElement("script");
    oNew.type = "text/javascript";
    oNew.textContent = code;
    document.getElementsByTagName("head")[0].appendChild(oNew);
}
};

/*Load script file. ScriptLoader will check if you try to load a file that has already been loaded (this check might be better, but I'm lazy).*/

ScriptLoader.LoadFile("Scripts/jquery-2.0.1.min.js");
ScriptLoader.LoadFile("Scripts/jquery-2.0.1.min.js");
/*this will be executed right after upper lines. It requires jquery to execute. It requires a HTML input with id "tb1"*/
$(function () { alert($('#tb1').val()); });
Комментарии (0)

There' s новое предложил стандарт ECMA, названный динамический импорт, недавно включенный в Хром и Сафари.

const moduleSpecifier = './dir/someModule.js';

import(moduleSpecifier)
   .then(someModule => someModule.foo()); // executes foo method in someModule
Комментарии (0)

Сохраните его хорошим, коротким, простым, и ремонтируемым!:]

// 3rd party plugins / script (don't forget the full path is necessary)
var FULL_PATH = '', s =
[
    FULL_PATH + 'plugins/script.js'      // Script example
    FULL_PATH + 'plugins/jquery.1.2.js', // jQuery Library 
    FULL_PATH + 'plugins/crypto-js/hmac-sha1.js',      // CryptoJS
    FULL_PATH + 'plugins/crypto-js/enc-base64-min.js'  // CryptoJS
];

function load(url)
{
    var ajax = new XMLHttpRequest();
    ajax.open('GET', url, false);
    ajax.onreadystatechange = function ()
    {
        var script = ajax.response || ajax.responseText;
        if (ajax.readyState === 4)
        {
            switch(ajax.status)
            {
                case 200:
                    eval.apply( window, [script] );
                    console.log("library loaded: ", url);
                    break;
                default:
                    console.log("ERROR: library not loaded: ", url);
            }
        }
    };
    ajax.send(null);
}

 // initialize a single load 
load('plugins/script.js');

// initialize a full load of scripts
if (s.length > 0)
{
    for (i = 0; i < s.length; i++)
    {
        load(s[i]);
    }
}

Этот кодекс - просто короткий функциональный пример, который мог требовать функциональности дополнительной функции для полной поддержки на любом (или данный) платформа.

Комментарии (0)

Техника, которую мы используем на работе, должна просить файл JavaScript, используя запрос AJAX и затем оценку () возвращение. Если you' ре, пользующееся библиотекой прототипа, они поддерживают эту функциональность в своем Аяксе. Требование запроса.

Комментарии (0)

jQuery решил это для меня с его .append () функция

  • используемый это, чтобы загрузить полный jQuery ui пакет

    /*

    • ИМЯ ФАЙЛА: project.library.js

    • ИСПОЛЬЗОВАНИЕ: грузы любая библиотека JavaScript */ вар dirPath = "../js/"; библиотека вара = [" функции js" " swfobject.js" " jQuery jeditable.mini.js" " jQuery ui 1.8.8.custom.min.js\U 0026\quot; " ui/jquery.ui.core.min.js" " ui/jquery.ui.widget.min.js" " ui/jquery.ui.position.min.js" " ui/jquery.ui.button.min.js" " ui/jquery.ui.mouse.min.js" " ui/jquery.ui.dialog.min.js" " ui/jquery.effects.core.min.js" " ui/jquery.effects.blind.min.js" " ui/jquery.effects.fade.min.js" " ui/jquery.effects.slide.min.js" " ui/jquery.effects.transfer.min.js"];

      для (сценарий вара в библиотеке) { $ (' head') .append (' < тип сценария =" text/javascript" src =" ' + dirPath + библиотека [сценарий] + ' " > </script> '); }

Использовать - в главе Вашего html/php/etc после того, как Вы импортируете jquery.js, как который Вы просто включали бы этот файл так, чтобы загрузить в полноте Вашей библиотеки, прилагающей его голове...

<script type="text/javascript" src="project.library.js"></script>
Комментарии (0)

Я потерян во всех этих образцах, но сегодня я должен был загрузить внешний .js от своего главного .js, и я сделал это:

document.write("<script src='https://www.google.com/recaptcha/api.js'></script>");
Комментарии (1)

Здесь простой с поддержкой IE и отзывом:

function loadScript(url, callback) {

    var script = document.createElement("script")
    script.type = "text/javascript";

    if (script.readyState) { //IE
        script.onreadystatechange = function () {
            if (script.readyState == "loaded" || script.readyState == "complete") {
                script.onreadystatechange = null;
                callback();
            }
        };
    } else { //Others
        script.onload = function () {
            callback();
        };
    }

    script.src = url;
    document.getElementsByTagName("head")[0].appendChild(script);
}

loadScript("https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function () {

     //jQuery loaded
     console.log('jquery loaded');

});
Комментарии (0)

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

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

Рассмотрение you' ve четыре сценария, названные 'script1.js, script2.js, script3.js, script4.js' тогда, Вы можете сделать это с применение async = ложный :

[
  '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 говорится: Я понятия не имею, какова эта «async» вещь, но это именно так происходит, я выполняю сценарии, добавленные через JS в заказе, они добавлены.

Сафари 5.0 говорит: Я понимаю «async», но не понимаю урегулирование это к «ложному» с JS. Я выполню Ваши сценарии, как только они приземляются в любом заказе.

IE < 10 говорит: Никакая идея о «async», но есть работа, используя «onreadystatechange».

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

Теперь, полный кодекс с IE < 10 работ:


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
Комментарии (1)

Что-то вроде этого...

<script>
     $(document).ready(function() {
          $('body').append('<script src="https://maps.googleapis.com/maps/api/js?key=KEY&libraries=places&callback=getCurrentPickupLocation" async defer>');
     });
</script>
Комментарии (0)

Здесь простой пример для функции, чтобы загрузить файлы JS. Важные моменты:

  • Вы don' t нужен jQuery, таким образом, Вы можете использовать это первоначально, чтобы загрузить также jQuery.js файл
  • это - async с отзывом
  • это гарантирует, что загружает только однажды, когда это держит вложение с отчетом нагруженных URL, таким образом избегая использования сети
  • вопреки jQuery '$ .ajax' или '$ .getScript' Вы можете использовать данные случаи, решение таким образом выходит с 'небезопасно-действующим' CSP. Просто используйте собственность 'script.nonce'
var getScriptOnce = function() {

    var scriptArray = []; //array of urls (closure)

    //function to defer loading of script
    return function (url, callback){
        //the array doesn't have such url
        if (scriptArray.indexOf(url) === -1){

            var script=document.createElement('script');
            script.src=url;
            var head=document.getElementsByTagName('head')[0],
                done=false;

            script.onload=script.onreadystatechange = function(){
                if ( !done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') ) {
                    done=true;
                    if (typeof callback === 'function') {
                        callback();
                    }
                    script.onload = script.onreadystatechange = null;
                    head.removeChild(script);

                    scriptArray.push(url);
                }
            };

            head.appendChild(script);
        }
    };
}();

<! - отрывок конца - >

Теперь Вы используете его просто

getScriptOnce("url_of_your_JS_file.js");
Комментарии (0)