[英]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
选项2
两种方法都可参考此文章: 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.