我在页面加载后动态地向head元素添加了一些<script>
标记。我理解脚本是异步加载的,但是我可以期望它们按照添加的顺序进行解析吗?
我在Firefox中看到了预期的行为,但在Safari或Chrome中却没有。查看Chrome开发人员工具和Firebug中的文档,两者都显示以下内容 -
<html>
<head>
...
<script type="text/javascript" src="A.js"></script>
<script type="text/javascript" src="B.js"></script>
</head>
...
</html>
然而,在查看资源加载视图时,chrome似乎会解析从服务器首先返回的任何一个,而firebug总是按照添加脚本标记的顺序加载它们,即使首先从服务器返回B也是如此。
我是否希望Chrome / Safari按指定顺序解析文件?在OS X 10.6.3上使用Chrome 5.0.375.29 beta
编辑(10/5/10):当我说解析时,我的意思是执行 - 可以看到积极解析的许多好处 - thx rikh
编辑(11/5/10):好的,所以我按照下面的juandopazo的说法进行了测试。但是我添加了一些组合,包括
我还尝试了脚本标签上'async'和'defer'属性的所有组合。
您可以在此处访问测试 - http://dyn-script-load.appspot.com/,并查看来源以查看其工作原理。加载的脚本只需调用update()函数。
首先要注意的是,只有上述第一和第三种方法并行运行 - 第二种方法依次执行请求。你可以在这里看到这个图表 -
图1 - 请求生命周期图 Request lifecycle Graph http://dyn-script-load.appspot.com/images/dynScriptGraph.png
有趣的是,jquery append()方法也阻止了getScript()调用 - 你可以看到它们都没有执行,直到所有append()调用完成,然后它们都并行运行。关于这一点的最后一点是,jQuery append()方法在执行后显然会从文档头中删除脚本标记。只有第一种方法会在文档中保留脚本标记。
Chrome结果
结果是Chrome始终执行第一个要返回的脚本,无论测试如何。这意味着所有测试'失败',除了jQuery append()方法。
图片2 - Chrome 5.0.375.29测试版结果
Chrome Results http://dyn-script-load.appspot.com/images/chromeDynScript.png
Firefox搜索结果
然而,在firefox上,如果使用第一个方法,并且async为false(即未设置),那么脚本将按顺序可靠地执行。
图3 - FF 3.6.3结果
FF Results http://dyn-script-load.appspot.com/images/ffDynScript.png
请注意,Safari似乎以与Chrome相同的方式提供不同的结果,这是有道理的。
另外,我在慢速脚本上只有500毫秒的延迟,只是为了保持开始 - >完成时间缩短。您可能需要刷新几次才能看到Chrome和Safari在所有内容上都失败。
在我看来,如果没有这样做的方法,我们就没有利用并行检索数据的能力,也没有理由不这样做(如firefox所示)。
答案 0 :(得分:2)
很抱歉回答我自己的问题,但已经有一段时间了,我们确实想出了一个解决方案。我们想出的是将javascript作为json对象中包含的文本同时加载,然后在加载它们之后使用eval()以正确的顺序执行它们。并发加载加有序执行。根据您的使用情况,您可能不需要json。粗略地说,这里有一些代码显示我们做了什么 -
// 'requests' is an array of url's to javascript resources
var loadCounter = requests.length;
var results = {};
for(var i = 0; i < requests.length; i++) {
$.getJSON(requests[i], function(result) {
results[result.id] = result;
...
if(--loadCounter == 0) finish();
});
}
function finish() {
// This is not ordered - modify the algorithm to reflect the order you want
for(var resultId in results) eval(results[resultId].jsString);
}
答案 1 :(得分:0)
根据我的理解,它们应按照它们在文档中出现的顺序执行。某些浏览器可能无法按顺序执行某些解析,但它们仍然必须以正确的顺序执行。
答案 2 :(得分:0)
不,你不能指望所有浏览器都会推迟两个脚本的执行,直到两个脚本都被加载(**尤其是当你动态添加它们时)。
如果您只想在加载B.js
后才在A.js
执行代码,那么最好的办法是向onload
添加一个A.js
回调设置变量和另一个变量一到B.js
检查是否已设置该变量,然后它在B.js
中执行必要的功能(如果有)(并且如果A.js
未加载,则启动一个计时器,定期检查,直到它已加载。)
答案 3 :(得分:0)
下载顺序和执行顺序不一样。在您的页面中,即使首先下载了B.js,浏览器的引擎也会等待A.js继续处理页面。
脚本肯定是按照它们在文档中出现的顺序处理的,而且也是在它们出现的位置处理的。
想象一下,如果不是这样的话,如果在jQuery库之前下载并处理了使用jQuery的小脚本,那么会有很多错误。
此外,当您在js文件中执行“document.write”时,它将显示在已声明脚本的位置。您无法访问在脚本声明之后出现的DOM对象。
这就是为什么有建议将脚本放在页面的最底部,以防止它们过早执行并减少页面的“感知加载时间”,因为浏览器的渲染引擎一旦脚本停止处理完毕。
麦克
编辑:如果使用javascript动态添加它们,我认为它们会按照及时添加的顺序进行处理。
答案 4 :(得分:0)
您可以从 a.js 加载 b.js 以100%确定...虽然我想自己明确回答这个问题,特别是同步ajax加载脚本。
答案 5 :(得分:0)
我正在研究一个像YUI 3那样动态加载模块的小库。我在这里创建了一个小测试,它加载了两个只将内容插入div的脚本。一个是常见的JS文件,另一个是等待3秒执行的PHP文件。
http://www.juandopazo.com.ar/tests/asyn-script-test.html
正如您所看到的,脚本在完成加载时执行,而不是按照每个浏览器中将它们附加到DOM的顺序执行。