Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
200 views
in Technique[技术] by (71.8m points)

javascript - Dynamic script addition should be ordered?

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

  1. Adding the script element to the head directly with javascript. (Tests A -> D)
  2. Adding the script element to the head using jquery's append() method. (Tests E -> H)
  3. '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).

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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 -

// '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);
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...