【问题标题】:javascript es5 async plugin architecturejavascript es5 异步插件架构
【发布时间】:2017-06-23 14:41:24
【问题描述】:

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

这是我想要配置我的插件的方式:

<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() 功能。

有什么想法/意见吗?

【问题讨论】:

    标签: javascript asynchronous plugins


    【解决方案1】:

    您可以使用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
    });
    

    【讨论】:

    • 抱歉,ES5 没有承诺。
    • 工作不允许使用任何外部库(性能、请求数量、更新问题等):(
    【解决方案2】:

    由于我没有收到有效的答案,我接受了我的非生产性想法:(

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

    对于那些想知道“then”功能的人,我做了以下事情:

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

    如果你们有更好的想法,请发帖!!!! :)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-08
      • 1970-01-01
      • 2018-09-13
      • 2012-01-02
      • 1970-01-01
      • 2014-10-28
      • 2011-05-24
      相关资源
      最近更新 更多