繁体   English   中英

动态包含JavaScript和等待

[英]Dynamically Include JavaScript and Wait

我想做的是动态地从Javascript中包含一个或多个js文件。 我知道有很多技术可以解决此问题,但是我正在寻找遵循以下规则的解决方案:

1)不要使用任何JS框架或库(jQuery,Prototype等)。

2)该脚本应停止执行,直到浏览器完全加载并解析了外部js文件为止。

#2背后的理由是外部js文件将包含函数定义,这些函数定义在包含脚本后必须立即使用。 在大多数情况下,在我开始调用这些函数之前,浏览器还没有时间解析js文件。

我不介意使用回调来知道脚本何时完成加载,但是:

1)我不提前知道将动态包含多少个脚本,因此我既不想也不可以编写一堆嵌套的回调。 我只需要知道它们什么时候都完成加载即可。

2)我的意思是,如果浏览器已缓存JavaScript,则尝试使用某种“加载”事件来触发回调可能无法正常工作。

编辑我应该从一开始就提到这是针对插件系统的,但是我想让我的问题/答案足够通用,以对其他人有所帮助。

用户可以定义要在数组中加载的插件。

plugins = [ 'FooPlugin', 'BarPlugin' ];

然后,我将遍历数组,并为每个插件加载js脚本:

for(var i = 0; i < plugins.length; i++) {
    loadScript('plugins/' + plugins[i] + '.js');
}

每个插件将自身推送到loaded_plugins数组(这是FooPlugin.js的示例)

load_plugins.push({
    name: 'FooPlugin',
    // Other plugin methods and properties here
});

从IE6开始跨浏览器工作。

document.loadScript = function (src, callback) {
    function script(src, onload) {
        var scriptTag = document.createElement('script');
        if (onload) scriptTag.onload = onload;
        scriptTag.src = src;
        scriptTag.type = 'text/javascript';
        return scriptTag;
    }
    function outer(tag) { 
        var d = document.createElement('div');
        d.appendChild(tag);
        return d.innerHTML;
    }
    if (!(src instanceof Array)) src = [src];
    var i, scr, 
        callbackId = 'dynCall_'+Math.floor(Math.random()*89999+10000);
        counter = src.length, 
        call = function () { if (--counter == 0) callback(); };
    if (!document.body) {
        window[callbackId] = function () {
            delete window[callbackId];
            if (callback instanceof Function) callback();
        };
        for (i=0; i<src.length; i++) document.write(outer(script(src[i])));
        document.write('<scr'+'ipt type="text/javascript">'+'window.'+callbackId+'();'+'</scr'+'ipt>');
        return;
    }
    for (i=0; i<src.length; i++) document.body.appendChild(script(src[i], call));
};

缩小/模糊:

(function(){document.loadScript=function(src,callback){function script(src,onload){var scriptTag=document.createElement('script');if(onload)scriptTag.onload=onload;scriptTag.src=src;scriptTag.type='text/javascript';return scriptTag}function outer(tag){var d=document.createElement('div');d.appendChild(tag);return d.innerHTML}if(!(src instanceof Array))src=[src];var i,scr,callbackId='dynCall_'+Math.floor(Math.random()*89999+10000);counter=src.length,call=function(){if(--counter==0)callback()};if(!document.body){window[callbackId]=function(){delete window[callbackId];if(callback instanceof Function)callback()};for(i=0;i<src.length;i++)document.write(outer(script(src[i])));document.write('<scr'+'ipt type="text/javascript">'+'window.'+callbackId+'();'+'</scr'+'ipt>');return}for(i=0;i<src.length;i++)document.body.appendChild(script(src[i],call))};document.loadScript.toString=function(){return'function loadScript() { [obfuscated] }'}})();

分支机构的简要说明:

如果调用loadScript的脚本标签在文档的头部或正文中,则由于DOM尚未存在,因此document.body将是未定义的。 因此,我们不能使用附加标签的标准方法,而必须使用doc write。 这样的好处是我们编写的标签必须按顺序发生,但是缺点是我们必须具有全局作用域回调函数。

同时,如果我们有document.body,那么我们就为正确做事(-ish-当周围没有任何库来帮助您正确地做它时做出了牺牲,因此.onload()是如此。 “将在脚本标签上引发很多事件,所以可能就可以了。)缺点(也许是?)是所有脚本都是异步加载的,因此我们需要在加载脚本时进行倒计时。

我知道,最简单(也是最可靠)的解决方案是只使用document.write在文件中插入一个新的脚本标签(当然,也可以根据需要)。

<script type="text/javascript">document.write('<' + 'script src="/assets/js/file.js" type="text/javascript"><\/script>');</script>

浏览器将按照脚本在文档中由script标签指定的顺序来(afaik)解析和执行脚本,也可以通过这种方式添加脚本。 因此,如果您将要执行的其余代码放在新的单独的脚本标记中,则应该会很好。

编辑 :这是一种(非常) 复杂的方法 ,其基础是使用“ elem = document.createElement('script')”,然后是elem.onreadystatechange(对于IE)和elem.onload。 将并行加载整批脚本,然后在它们全部存在时触发回调。 过去曾使用过这种方法,当时浏览器仍然一次最多只加载一个脚本以加快加载速度(它是基于某个目的类似的脚本)。 用法示例:

Loader.script( [
    './js/jquery/jquery.jmap.js',
    './js/jquery/jquery.getUrlParam.js',
    './js/jquery/jquery.form.js',
    './js/jquery/jquery.gettext.js',
    './js/jquery/jquery.scrollTo.js',
    './js/jquery/jquery.prettydate.js'
  ], { complete: function() {
    // do your thing
  }
})

几种可能的解决方法 我将编写步骤,而不是代码。

选项1

  1. 通过将JS文件放置在带有标签的元素中来加载JS文件。
  2. 在触发setTimout()之后立即检查加载的JS文件中的变量。
  3. 重复#2直到变量存在或达到maxCounter(maxCounter = 10),这样您才不会永远坐在那里。
  4. 变量存在后,继续下一个JS文件,然后再次从步骤1开始。

选项2

  1. 使用Ajax方法。
  2. 使用Ajax调用JS文件。
  3. 将结果附加到以下文章中的使用说明中。
  4. 将setTimeout()函数设置为几秒钟,然后处理脚本或检查类似于选项#1的变量,并重复超时直到出现变量。

两种方法都可参考此文章: http : //www.hunlock.com/blogs/Howto_Dynamically_Insert_Javascript_And_CSS

困难的部分是您要让您的代码知道浏览器何时加载和处理每个JS文件。 由于计算机和浏览器的不同,处理JS文件所需的时间也会有所不同,因此,如果没有JS文件中的某些逻辑,则很难进行跟踪。

我更喜欢这样的方法:

1 在可以处理动态逻辑的服务器(php,java,.NET等)上制作一个Javascript请求标签,ajax。

2 传递页面上已经存在的回调函数,该函数知道您需要知道多少个其他JS文件。 甚至在回调中包含一个索引参数(类似于myCallback(5)),以便您知道自己的位置。

1-2a 您可以手动将回调函数附加到所有JS文件中,然后让该函数管理JS队列,而无需JS文件具有除回调函数以外的任何知识。

3 让服务器将回调附加到要返回的JS文件中。

4 一旦处理完JS,就会触发回调函数,它将为您管理其他JS文件的加载。

那个怎么样?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM