архитектура плагина javascript es5 async

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

вот как я хотел бы настроить мои Плагины:

<script id="target_root" src="assets/js/target/target.js" async="true"></script>
<script>
    var target = target || {};
    target.cmd = target.cmd || [];

    target.cmd.push(function () {
        target.loadPlugins([
            {"name": "root", "src": "assets/js/target/target.root.js"},
            {"name": "krux", "src": "assets/js/target/target.krux.js"}
        ]).then(
            target.init([
                {
                    'plugin': 'root',
                    'opts': {
                        'foo': 'bar'
                    }
                },
                {
                    'plugin': 'krux',
                    'opts': {
                        'foo': 'bar'
                    }
                }
            ])
        )
    });
</script>

поскольку я буду использовать встроенные функции (в DOM), я подумал об использовании очереди команд, которая при загрузке будет вызывать все выталкиваемые функции (немного похоже на googletag cmd DFP).

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

вот вам мой скрипт:

var target = (function(root, w, d, c) {
    var queueIndex = 0,
        amountPluginsLoaded = 0,
        pluginsLoaded = [];

    root.cmd = {
        'queue': root && root.cmd ? root.cmd : [],
        'push': function(fn) {
            this.queue.push(fn);
            this.next();
        },
        'next': function() {
            if (this.queue.length > 0) {
                this.queue.shift()();
            }
        }
    };

    root.init = function(plugins) {

    };

    root.loadPlugins = function(plugins) {
        var i = 0,
            len = plugins.length;
        for(; i < len; i++) {
            _loadExternalJS(plugins[i]);
        }
    };

    function _loadExternalJS(plugin) {
        var scriptRoot = d.getElementById('target_root'),
            scriptElement = d.createElement('script');

        scriptElement.setAttribute('type', 'text/javascript');
        scriptElement.setAttribute('async', 'true');
        scriptElement.onload = function() {
            amountPluginsLoaded++;
            pluginsLoaded.push(plugin.name);
        };
        scriptElement.setAttribute('src', plugin.src);
        scriptRoot.parentNode.insertBefore(scriptElement, scriptRoot.nextSibling);
    }

    function _initPlugin(plugin) {

    }

    for (; queueIndex < root.cmd.queue.length; queueIndex++) {
        root.cmd.next();
    }
}(target || {}, window, document, console));

здесь у вас есть основные функции cmd, которые будут переопределены и загрузка каждого из сценариев.

чего я не могу понять, так это как запустить then(). Я полагаю, вы будете отслеживать его в _loadExternalJS() в it's onload event (как вы можете видеть в коде). Но Просто добавьте if (amountPluginsLoaded === pluginsLoaded.length) { fire all inits } кажется непродуктивным, а не тем, что принадлежит функции. вот почему я хотел бы реализовать некоторые функции then ().

какие-либо идеи/мнения?

2 ответов


можно использовать обещание и обещание.все!--4--> для проверки все они загружены.

root.loadPlugins = function(plugins) {
    var promiseArray = plugins.map(function(plugin){
         return _loadExternalJS(plugin);
    });
    return Promise.all(promiseArray);
};

function _loadExternalJS(plugin) {
    return new Promise((resolve, reject) => {
       var scriptRoot = d.getElementById('target_root'),
           scriptElement = d.createElement('script');

       scriptElement.setAttribute('type', 'text/javascript');
       scriptElement.setAttribute('async', 'true');
       scriptElement.onload = function() {
          amountPluginsLoaded++;
          pluginsLoaded.push(plugin.name);
          resolve(plugin.name);
       };
       scriptElement.setAttribute('src', plugin.src);
       scriptRoot.parentNode.insertBefore(scriptElement, scriptRoot.nextSibling);
   });
}

затем

root.loadPlugins().then(function(){
    //initialize plugins
});

Как я не получил ответа, я взял свою непродуктивную идею :(

function _loadExternalJS(elem) {
    var scriptRoot = d.getElementById('target_root'),
        scriptElement = d.createElement('script'),
        isElemPlugin = elem.isPlugin || typeof elem.isPlugin === "undefined",
        loadAsync = elem.async || typeof elem.async === "undefined";

    scriptElement.setAttribute('type', 'text/javascript');
    scriptElement.setAttribute('async', loadAsync);

    if (isElemPlugin) {
        scriptElement.onload = function() {
            jsLoaded++;
        };
    }

    scriptElement.setAttribute('src', elem.src);
    scriptRoot.parentNode.insertBefore(scriptElement, scriptRoot.nextSibling);
}

для тех, кто интересуется функциональностью "тогда", я сделал следующее:

target.init = function (plugins) {
    //do something

    return {
        'then': _then
    }
};

function _then(fn) {
    var loaded;
    loaded = w.setInterval(function () {
        if (jsLoaded === pluginList.length) {
            w.clearInterval(loaded);
            fn();
        }
    }, 10);
}

Если у кого-то из вас есть лучшая идея, пожалуйста, напишите!!!! :)