Определите, когда список сценариев загружен в javascript (используя пространства имен). - PullRequest
0 голосов
/ 22 марта 2012

Я сделал фреймворк пространств имен для javascript. Я загружаю некоторые плагины (файлы .js), которые динамически добавляются в HTML.

Я собираюсь попытаться упростить код.

Эта функция используется для динамической загрузки JS. Функция обратного вызова вызывается после загрузки файла .js. Учтите, что следующий код уже был выполнен.

MYNAMESPACE.plugins = ["plugin1", "plugin2"];
MYNAMESPACE.getJS = {
    get: function (url, callback) {
        var script = document.createElement("script");
        var head = document.getElementsByTagName('head')[0];
        script.type = "text/javascript";
        script.src = url;
        head.insertBefore(script, head.firstChild)
        script.onload = callback;
        script.onreadystate = callback;
        return script;
        }
};

У меня есть функция init, которая загружает плагины, содержащиеся в MYNAMESPACE.plugins, следующим образом:

MYNAMESPACE.init = function (callback) {
    for (index in MYNAMESPACE.plugins) {
        plugin = MYNAMESPACE.plugins[index];
        MYNAMESPACE.getJS.get(plugin + '.js', function ()
         {
              // This callback is executed when the js file is loaded
         });
    }
    // Here I want to execute callback function, but after all the callbacks in the for loop have been executed.  Something like: if (alljsloaded) callback();
}

В моем HTML у меня есть следующий тег script:

<html>
    <head>
    <script type="text/javascript">
        $(document).ready(function () {
            MYNAMESPACE.init(); 

            // The following line is not executed correctlybecause init finished before the scripts are loaded and the functionOnPlugin1 is undefined.
            MYNAMESPACE.functionOnPlugin1();
        });
    </script>
    </head>
    <body>
    </body>
</html>

И я хочу изменить это на что-то вроде этого:

<html>
    <head>
    <script type="text/javascript">
        $(document).ready(function () {
            MYNAMESPACE.init(function() { MYNAMESPACE.functionOnPlugin1(); });  
        });
    </script>
    </head>
    <body>
    </body>
</html>

Но я не знаю, как изменить функцию MYNAMESPACE.init (), чтобы она выполняла обратный вызов после загрузки ВСЕХ скриптов плагина.

Есть идеи? Возможно, используя замыкания.

Ответы [ 2 ]

3 голосов
/ 22 марта 2012
  1. Используйте for(;;) для циклического перемещения по массиву, , а не for(.. in ..).
  2. Создайте счетчик в функции, увеличивайте его при каждой загрузке скрипта.Когда он достигнет количества сценариев, вызовите функцию обратного вызова.

Код:

MYNAMESPACE.init = function (callback) {
    var allPluginsLength = MYNAMESPACE.plugins.length;
    var loadedCount = 0;
    if (allPluginsLength === 0) callback(); // No plugins, invoke callback.
    else for (var index=0; index<allPluginsLength; i++) {
        plugin = MYNAMESPACE.plugins[index];
        MYNAMESPACE.getJS.get(plugin + '.js', function () {
              // This callback is executed when the js file is loaded
              if (++loadedCount == allPluginsLength) {
                  callback();
              }
         });
    }
}

Также, измените ваш getJS.get метод.В настоящее время callback всегда выполняется при изменении состояния, что нежелательно.Чтобы предотвратить повторное выполнение обратного вызова, можно использовать следующее:

    script.onload = function() {
        callback && callback();
        callback = false;
    };
    // onreadystatechange instead of onreadystate, btw.
    script.onreadystatechange = function() {
        if (this.readyState == 'complete') {
            callback && callback();
            callback = false;
        }
    };
  • callback && callback(), чтобы обеспечить наличие обратного вызова.Если это так, то он вызывается.
  • После вызова обратного вызова он немедленно удаляется (callback = null).
    Это необходимо, потому что события onload и onreadystatechange могут запускаться, когда скриптзагрузил.Без предложенного мной кода обратный вызов будет вызываться несколько раз для одного скрипта.
1 голос
/ 22 марта 2012

Некоторые изменения вроде этого должны работать:

MYNAMESPACE.init = function (callback) {
    var remaining = MYNAMESPACE.plugins.length;
    for (index in MYNAMESPACE.plugins) {
        plugin = MYNAMESPACE.plugins[index];
        MYNAMESPACE.getJS.get(plugin + '.js', function ()
         {
              // This callback is executed when the js file is loaded
              remaining = remaining - 1;
              if (remaining === 0)
              {
                  callback();
              }
         });
    }
}
...