动态脚本添加应该订购吗?
我在页面加载后动态添加一些 标签到 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>
然而,查看资源加载视图,chrome似乎解析首先从服务器返回的内容,而firebug总是按照添加脚本标签的顺序加载它们,即使 B 首先从服务器返回。
我应该期望 Chrome/Safari 按指定的顺序解析文件吗?在 OS X 10.6.3 上使用 Chrome 5.0.375.29 beta
编辑(10/5/10):当我说解析时,我的意思是执行 - 可以看到积极解析的许多好处 - thx rikh
编辑(10/5/10):好的所以我按照下面 juandopazo 的思路做了一个测试。不过,我添加了一些内容的组合,包括
- 使用 javascript 直接将脚本元素添加到头部。 (测试A -> D)
- 使用jquery 的append() 方法将脚本元素添加到头部。 (测试 E -> H)
- 使用 jquery 的 getScript() 方法“加载”脚本。 (测试 I -> L)
我还尝试了脚本标签上“async”和“defer”属性的所有组合。
您可以在此处访问测试 - http://dyn-script-load.appspot.com/,并查看源代码以了解其工作原理。加载的脚本只需调用 update() 函数即可。
首先要注意的是,只有上述第 1 种和第 3 种方法是并行操作的 - 第二种方法按顺序执行请求。您可以在此处查看该图 -
图 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 beta 结果
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 所示)。
I'm adding some <script>
tags dynamically to the head element after page load. I understand the scripts are loaded asynchronously, but can I expect them to be parsed in the order they are added?
I'm seeing the expected behaviour in Firefox, but not in Safari or Chrome. Looking at the document in Chrome developer tools and Firebug, both show the following -
<html>
<head>
...
<script type="text/javascript" src="A.js"></script>
<script type="text/javascript" src="B.js"></script>
</head>
...
</html>
However looking at the resource loading view, chrome seems to parse whichever is returned first from the server, while firebug always loads them in the order the script tags were added, even when B is returned first from the server.
Should I expect Chrome/Safari to parse the files in the specified order? Using Chrome 5.0.375.29 beta on OS X 10.6.3
EDIT (10/5/10): When I say parse, I mean execute - can see many benefits of aggressive parsing - thx rikh
EDIT (11/5/10): Ok so I put together a test along the lines of that by juandopazo below. However I have added a combination of things, including
- Adding the script element to the head directly with javascript. (Tests A -> D)
- Adding the script element to the head using jquery's append() method. (Tests E -> H)
- 'Loading' the script with jquery's getScript() method. (Tests I -> L)
I also tried all combination of the 'async' and 'defer' attributes on the script tags.
You can access the test here - http://dyn-script-load.appspot.com/, and view source to see how it works. The loaded scripts simply call the update() function.
The first thing to note, is that only the 1st and 3rd methods above operate in parallel - the 2nd executes requests sequentially. You can see a graph of this here -
Image 1 - Graph of Request Lifecycle
Request lifecycle Graph http://dyn-script-load.appspot.com/images/dynScriptGraph.png
It's also interesting that the jquery append() approach also blocks getScript() calls - you can see that none of them execute until all of the append() calls are complete, and then they all run in parallel. Final note on this is that the jQuery append() method apparently removes the script tags from the document head once they have executed. Only the first method leaves the script tags in the document.
Chrome Results
The results are that Chrome always executes the first script to return, regardless of the test. This means all the test 'fail', except the jQuery append() method.
Image 2 - Chrome 5.0.375.29 beta Results
Chrome Results http://dyn-script-load.appspot.com/images/chromeDynScript.png
Firefox Results
On firefox, however, it appears that if the first method is used, and async is false (i.e. not set), then the scripts will reliably execute in order.
Image 3 - FF 3.6.3 Results
FF Results http://dyn-script-load.appspot.com/images/ffDynScript.png
Note that Safari seems to give varied results in the same manner as Chrome, which makes sense.
Also, I only have a 500ms delay on the slow script, just to keep the start->finish time down. You may have to refresh a couple of times to see Chrome and Safari fail on everything.
It seems to me that without a method for doing this, we are not taking advantage of the ability to retrieve data in parallel, and there is no reason why we shouldn't (as firefox shows).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
很抱歉回答我自己的问题,但已经有一段时间了,我们确实找到了解决方案。我们想到的是将 JavaScript 作为包含在 json 对象中的文本同时加载,然后在它们全部加载后使用 eval() 以正确的顺序执行它们。并发加载加上有序执行。根据您的用例,您可能不需要 json。粗略地说,这里有一些代码显示了我们所做的事情 -
Sorry for answering my own question, but its been a while and we did come up with a solution. What we came up with was to load the javascript concurrently as text contained in a json object, and then used eval() once they were all loaded to execute them in the correct order. Concurrent load plus ordered execution. Depending on your use case you may not need the json. Roughly, here is some code that shows what we did -
据我了解,它们应该按照它们在文档中出现的顺序执行。某些浏览器可能能够无序地执行一些解析,但它们仍然必须以正确的顺序执行。
As I understand it, they are meant to be executed in the order they appear in the document. Some browser might be able to perform some parsing out of order, but they would still have to be executed in the correct order.
不,您不能期望所有浏览器都会推迟两个脚本的执行,直到两个脚本都加载完毕(**特别是当您动态添加它们时)。
如果您想仅在加载
A.js
后才执行B.js
中的代码,那么最好的选择是将onload
回调添加到 < code>A.js 设置一个变量,另一个变量设置为B.js
,检查该变量是否已设置,然后在 B 中执行必要的函数。 js(如果已加载)(如果A.js
尚未加载,它会启动一个计时器,定期检查直到加载)。No, you cannot expect that all browsers will defer execution of both scripts until both are loaded (**especially when you are adding them dynamically).
If you want to execute code in
B.js
only afterA.js
is loaded then your best bet is to add anonload
callback toA.js
that sets a variable and another one toB.js
that checks to see if that variable has been set, then it executes the necessary function inB.js
if it has (and ifA.js
has not loaded, it starts a timer that periodically checks until it has loaded).下载顺序和执行顺序不是一回事。在你的页面中,即使先下载了 B.js,浏览器的引擎也会等待 A.js 继续处理页面。
脚本肯定会被处理,不仅按照它们在文档中出现的顺序,而且还按照它们出现的位置。
想象一下,如果不是这样,如果您使用 jQuery 的小脚本在 jQuery 库之前下载和处理,将会出现很多错误。
另外,当您在 js 文件中执行“document.write”时,它会出现在声明脚本的位置。您也无法访问脚本声明之后出现的 DOM 对象。
这就是为什么建议将脚本放在页面的最底部,以防止它们执行得太快并减少页面的“感知加载时间”,因为一旦处理脚本,浏览器的渲染引擎就会停止。
迈克
编辑:如果它们是用javascript动态添加的,我认为它们会按照它们及时添加的顺序进行处理。
The download order and the execution order is not the same thing. In your page, even if B.js is downloaded first, the browser's engine will wait for A.js to continue processing the page.
The scripts are definitely processed, not only in the order they appeared in the document, but also at the place they appeared.
Imagine if it wouldn't be like that, there would be many errors if your little script that uses jQuery is downloaded and processed before the jQuery library.
Also, when you do a "document.write" in a js file, it appears where the script has been declared. You can't access DOM objects that are appearing after the script declaration neither.
This is why there are recommendations to put scripts at the very bottom of the page, to prevent their execution too soon and decrease the "perceived load time" of the page, because the browser's rendering engine is stopped as soon as a script is processed.
Mike
EDIT: if they are added dynamically with javascript, I think they are processed in the order they were added in time.
您可以从 a.js 加载 b.js 来 100% 确定...尽管我自己想要这个问题的明确答案,尤其是同步 ajax 加载脚本。
You could load b.js from a.js to be 100% sure ... although I'd like the definitive answer to this question myself, especially with sync ajax loading of scripts.
我在研究一个像 YUI 3 一样动态加载模块的小库时对此进行了调查。我在这里创建了一个小测试,加载两个仅将内容插入 div 的脚本。一个是普通的JS文件,另一个是等待3秒执行的PHP文件。
http://www.juandopazo.com.ar/tests/asyn- script-test.html
如您所见,在每个浏览器中,脚本在完成加载时执行,而不是按照将它们附加到 DOM 的顺序。
I was investigating this while working on a little library that loads modules dynamically like YUI 3. I created a little test here that loads two scripts that just insert content into divs. One is a common JS file and the other is a PHP file that waits 3 seconds to execute.
http://www.juandopazo.com.ar/tests/asyn-script-test.html
As you can see, scripts are executed when they finish loading, and not in the order in which you append them to the DOM, in every browser.