javascript es5 异步插件架构

标签 javascript asynchronous plugins

我正在尝试找出一种方法来构建一个能够注入(inject)插件的新工作框架。这个想法是让每个文件异步加载。

以下是我希望如何配置我的插件:

<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 中),所以我想到了使用一个命令队列,它在加载时会调用所有推送的函数(有点像 DFP 的 googletag cmd)。

如前所述,每个插件都将异步加载,因此每个插件的初始化应该仅在所有插件都加载后才开始(因此有 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()。我想您会在它的 onload 事件中的 _loadExternalJS() 中跟踪它(如您在代码中所见)。但是简单地添加一个 if(amountPluginsLoaded === pluginsLoaded.length) { fire all inits } 似乎没有效果,而且不属于函数。这就是为什么我喜欢实现一些 then() 功能。

有什么想法/意见吗?

最佳答案

你可以使用 promisepromise.all检查所有这些都已加载。

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
});

关于javascript es5 异步插件架构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44724164/

相关文章:

javascript - 使用 PHP(或 JS)脚本单击外部按钮

javascript - 如何使弹出窗口在关闭后停留在同一区域

java - 异步网络服务 SOAP

android - 开发 Ionic/Cordova 插件 - 插件无法构建

java - 在不打开eclipse的情况下卸载eclipse的插件

android - 当前维护的cordova-plugin-crosswalk-webview 有什么替代方案吗?

javascript - 使用带有 CDN 的工作箱时缓存存储为空

javascript - 如何将值从js传递到html.erb渲染函数

c# - 微服务之间如何建立通信?

javascript - 如何在 catch 语句之外的 async/await 中拒绝?