document.createElement ('script') добавление двух скриптов с одним обратным вызовом

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

var script = document.createElement("script");
script.src = "http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js";
script.onload = script.onreadystatechange = callback;
document.body.appendChild( script );

Я мог бы сделать это, связав обратные вызовы, но это кажется плохой практикой (мне не нужна глупая цепочка из 20 методов обратного вызова, когда мне нужно загрузить больше скриптов). Идеи?


person user199085    schedule 08.12.2009    source источник
comment
Почему бы вам не добавить этот сценарий в HTML, чтобы загрузить его с помощью JavaScript?   -  person RaYell    schedule 08.12.2009
comment
Я делаю небольшой код, который нужно вставить в html других людей, чтобы встроить свой материал. Мне нужно вставить только пустой div и ссылку на мой файл javascript.   -  person user199085    schedule 08.12.2009
comment
@kdiegert: эта ссылка на ваш файл js вставлена: вы имеете в виду через <script src="my.js"></script>?   -  person Crescent Fresh    schedule 08.12.2009
comment
да, поэтому вставляемый код будет выглядеть следующим образом: ‹div id = myDiv› ‹/div› ‹script src = my.js? arguments = arguments› ‹/script›   -  person user199085    schedule 08.12.2009
comment
css-tricks.com/snippets/javascript/   -  person t1gor    schedule 12.11.2014


Ответы (4)


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

function loadScripts(array,callback){
    var loader = function(src,handler){
        var script = document.createElement("script");
        script.src = src;
        script.onload = script.onreadystatechange = function(){
            script.onreadystatechange = script.onload = null;
            handler();
        }
        var head = document.getElementsByTagName("head")[0];
        (head || document.body).appendChild( script );
    };
    (function run(){
        if(array.length!=0){
            loader(array.shift(), run);
        }else{
            callback && callback();
        }
    })();
}

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

loadScripts([
   "http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js",
   "http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js"
],function(){
    alert('All things are loaded');
});

Надеюсь, это поможет

person nemisj    schedule 08.12.2009
comment
В этом могут помочь aysnc.parallel или async.series github.com/caolan/async - person Alexander Mills; 08.04.2015
comment
arguments.callee выдает ошибку в строгом режиме: из developer.mozilla.org / en-US / docs / Web / JavaScript / Reference / arguments.callee больше не поддерживается. В нормальном коде arguments.callee относится к включающей функции. Этот вариант использования слабый: просто назовите включающую функцию! Более того, arguments.callee существенно затрудняет оптимизацию, такую ​​как встраивание функций, потому что должна быть предусмотрена возможность предоставления ссылки на невыстроенную функцию при доступе к arguments.callee. - person Gabriel Luethje; 25.08.2016
comment
@GabrielLuethje, изменил его на именованную функцию - person nemisj; 13.09.2016
comment
Не могли бы вы подробно задокументировать то, что вы там делали? - person SumNeuron; 09.05.2017
comment
Это решение было полезно при использовании SinglePageApplication, например Ember. - person jalilIrfan; 11.09.2017

Из-за ошибки в Internet Explorer программа рекурсивного загрузчика nemisj работает некорректно в IE. Можно решить, установив задержку рекурсивного вызова, например:


function loadScripts(array,callback){  
    var loader = function(src,handler){  
        var script = document.createElement("script");  
        script.src = src;  
        script.onload = script.onreadystatechange = function(){  
          script.onreadystatechange = script.onload = null;  
          if(/MSIE ([6-9]+\.\d+);/.test(navigator.userAgent))window.setTimeout(function(){handler();},8,this);  
          else handler();  
        }  
        var head = document.getElementsByTagName("head")[0];  
        (head || document.body).appendChild( script );  
    };  
    (function(){  
        if(array.length!=0){  
                loader(array.shift(),arguments.callee);  
        }else{  
                callback && callback();  
        }  
    })();  
}  

Этот небольшой прием делает это и часто является решением в IE, когда возникает необъяснимая проблема, что происходит слишком часто.

person gerteb    schedule 28.04.2011

Поскольку scriptaculous требует прототипа, вам придется связать слушателей с помощью любого метода, который вы используете для загрузки этих скриптов.

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

Если вам нужно загрузить 10-20 скриптов, я бы порекомендовал объединить скрипты заранее, используя такой инструмент, как Объединитель.

person Eric Bréchemier    schedule 08.12.2009
comment
фактически, этот сценарий именно и был разработан для решения LABjs. - person Kyle Simpson; 20.05.2011

Вы можете обещать обратные вызовы скрипта .onload и .onerror, а затем использовать Promise.all, чтобы дождаться всего обещания разрешить перед продолжением выполнения, зависящего от этих сценариев.

Вот пример:

const loadScript = url => 
  new Promise((resolve, reject) => {
    const script = document.createElement("script");
    script.src = url;
    script.onload = resolve;
    script.onerror = e => 
      reject(Error(`${url} failed to load`))
    ;
    document.head.appendChild(script);
  })
;

const scriptURLs = [
  "https://unpkg.com/htm",
  "https://unpkg.com/[email protected]/dist/axios.min.js",
  "https://cdnjs.cloudflare.com/ajax/libs/d3/6.3.1/d3.min.js",
  // ...
];

Promise.all(scriptURLs.map(loadScript))
  .then(async () => {
    /* Use your scripts here */
    console.log("proving scripts loaded:");
    axios.get("http://jsonplaceholder.typicode.com/users");
    console.log(d3.csvParse("a,b\n3,4\n5,6"));
    const html = htm.bind((t, p, ...c) => ({t, p, c}));
    console.log(html`<h1 id=hello>Hello world!</h1>`);
  })
  .catch(err => console.error(err))
;

person ggorlen    schedule 16.12.2020