是否应该订购动态脚本?

haw*_*ett 7 javascript dynamic-script-loading

<script>在页面加载后动态地向head元素添加了一些标签.我理解脚本是异步加载的,但是我可以期望它们按照添加的顺序进行解析吗?

我在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>
Run Code Online (Sandbox Code Playgroud)

但是,在查看资源加载视图时,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的说法进行了测试.但是我添加了一些东西,包括

  1. 使用javascript直接将脚本元素添加到头部.(测试A - > D)
  2. 使用jquery的append()方法将脚本元素添加到头部.(测试E - > H)
  3. 使用jquery的getScript()方法"加载"脚本.(测试I - > L)

我还尝试了脚本标签上"async"和"defer"属性的所有组合.

您可以在此处访问测试 - http://dyn-script-load.appspot.com/,并查看源代码以了解其工作原理.加载的脚本只需调用update()函数.

首先要注意的是,只有上述第一和第三种方法并行运行 - 第二种方法依次执行请求.你可以在这里看到这个图表 -

图1 - 请求生命周期
请求生命周期图表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结果http://dyn-script-load.appspot.com/images/chromeDynScript.png

Firefox结果

但是,在firefox上,如果使用第一个方法,并且async为false(即未设置),那么脚本将按顺序可靠地执行.

图3 - FF 3.6.3结果
FF结果http://dyn-script-load.appspot.com/images/ffDynScript.png

请注意,Safari似乎以与Chrome相同的方式提供不同的结果,这是有道理的.

此外,我在慢速脚本上只有500毫秒的延迟,只是为了保持开始 - >结束时间.您可能需要刷新几次才能看到Chrome和Safari在所有内容上都失败了.

在我看来,没有这样做的方法,我们没有利用并行检索数据的能力,并且我们没有理由不应该(如firefox所示).

haw*_*ett 3

很抱歉回答我自己的问题,但已经有一段时间了,我们确实找到了解决方案。我们想到的是将 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);
}
Run Code Online (Sandbox Code Playgroud)