views:

546

answers:

3

I was wondering if there are any available resources that describe how a browser's cursor executes Javascript.

I know it loads and executes tags when a page loads, and that you can attach functions to various window events, but where things get fuzzy is when, for instance, I retrieve a remote page via AJAX and put its contents into a div.

If that remote page has loads script libraries like <script src="anotherscript.js" />, when is "anotherscript.js" loaded and its contents executed?

What happens if I included "anotherscript.js" on my current page, and then I load some remote content which has a duplicate include of this script? Does it overwrite the original one? What if the original "anotherscript.js" has a var in it whose value I altered, and then I reload that file... do I lose the original value or is the second inclusion of this script ignored?

If I load some procedural Javascript via AJAX, when is it executed? Immediately after I do mydiv.innerHTML(remoteContent)? Or is it executed before that?

A: 

If you just stuff a block of HTML containing script tags into your DOM with "innerHTML", the script tags won't be executed at all. When you load stuff with something like jQuery, code in that library explicitly handles finding and executing the scripts.

It's not precisely accurate, but you can basically think of the processing of a <script> tag as if the whole contents of the tag (i.e., the script body) were executed with eval(). If the script declares global (window) variables, then old values are overwritten.

Script tags are processed in the order that they appear. Of course the code inside the script blocks may be set up so that what it does upon initial execution is to defer the real processing until later. Lots of jQuery setup/initialization code will do that.

Pointy
I was told that innerHTML will parse and execute JavaScript. That's why you should be careful around innerHTML :)But maybe that's only true for the content of a tag, not for a .js-file linked in src= ?
Adrian Schmidt
Well try it :-) I know that jQuery explicitly does different stuff when it detects that a string argument to `html()` doesn't have any script tags in it - specifically, it just uses `innerHTML()`.
Pointy
@Adrian: Re *"...I was told that innerHTML will parse and execute JavaScript. That's why you should be careful around innerHTML..."* Well, you *never* want to assign user-provided content directly to an element via `innerHTML` if that's what you're being careful of, but I'm not aware of a browser that executes `script` tags (inline or referencing an external file) when you do.
T.J. Crowder
@T.J.: Internet Explorer will if you scratch it in just the right spot behind it's ear: http://stackoverflow.com/questions/1891947/are-dynamically-inserted-script-tags-meant-to-work/1891999#1891999
Andy E
+8  A: 

The answer varies depending on where the script tag is and how you've added it:

  1. Script tags inline with your markup are executed synchronously with the browser's processing of that markup (except, see #2), and so if -- for instance -- those tags reference external files, they tend to slow down the processing of the page. (This is so the browser can handle document.write statements, which change the markup they're processing.)

  2. Script tags with the defer attribute may, on some browsers, not be executed until after the DOM has been fully rendered. Naturally these can't use document.write. (Similarly there's an async attribute that makes the script asynchronous, but I don't know much about it or how well it's supported; details.)

  3. Script tags in content you assign to elements after DOM load (via innerHTML and similar) are not executed at all, barring your use of a library like jQuery or Prototype to do it for you. (With one exception pointed out by Andy E: On IE, if they have a defer attribute, it will execute them. Doesn't work in other browsers.)

  4. If you append an actual script element to the document via Element#appendChild, the browser executes that script immediately (and you can happily remove the element if you like, the script has already been executed and processed). (You would normally append those to the head element, but in practice it doesn't really matter.)

  5. Script inside event handlers on attributes (<a href='#' onclick='myNiftyJavaScript();'>) rather than in a script tag is executed when the relevant event occurs.


Edit I was working away at my Real Job and suddenly my hindbrain said "You know, you've been told they won't be executed if you assign them to innerHTML, but have you personally checked?" And I hadn't, so I did -- FWIW:

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<title>Script Test Page</title>
<style type='text/css'>
body {
    font-family: sans-serif;
}
</style>
<script type='text/javascript'>
function addScript()
{
    var str, div;

    div = document.getElementById('target');
    str = "Content added<" + "script type='text/javascript'>alert('hi there')<" + "/" + "script>";
    alert("About to add:" + str);
    div.innerHTML = str;
    alert("Done adding script");
}
</script>
</head>
<body><div>
<input type='button' value='Go' onclick='addScript();'>
<div id='target'></div>
</div></body>
</html>

The alert from the script doesn't appear on IE7, FF3.6, or Chrome4 (I haven't bothered to check others, I'm meant to be working :-) ). Whereas if you append elements as shown here, the script gets executed.

T.J. Crowder
You're so smart.
Pointy
@Pointy: LOL! See, this is the benefit of your not meeting me in person. If you did, you'd immediately realize you've formed a mistaken impression... ;-)
T.J. Crowder
@T.J. Crowder: Wow... thanks for all the details and the test as well. I'm pretty sure when I used jQuery.html(...) it was executing the scripts within immediately, but I didn't realize that was jQuery and not default javascript behavior. I guess I need to look into the jQuery code because I'm pretty sure the API guide didn't mention this.
RenderIn
@T.J.: add the `defer` attribute to the `innerHTML = ` example you tried and try it again in IE :-)
Andy E
@Andy: !! Cool, thanks! I Did Not Know That. :-) Looks like it's just IE, though. Still, good to know.
T.J. Crowder
@RI: No worries, stuff I've picked up along the way. Surprising about the jQuery docs not talking about it, but I'm not immediately seeing it either. (http://docs.jquery.com/Attributes/html) Prototype's docs do.
T.J. Crowder
A: 

Modern browsers can load multiple scripts concurrently, and not all browsers will execute them in the order they were called in the source code- often the first script downloaded, or a script that has been cached, will be interpreted 'out of order'.

A script that defines methods or objects will overwrite any with the same identifiers that were previously defined.

Write scripts so that they can not overwrite anything until you call a method defined in the script (and don't call the method if it is not yet defined.)

One reason not to remove a script tag after its script has been evaluated is that it gives you an easy way to tell if the script has already been loaded- though if you are careful with your method names, checking for a method that is only defined in one script will tell you if the script is loaded.

kennebec
They can certainly *download* more than one at a time, but barring use of the `defer` attribute, I've never heard of a browser *executing* a script out of document order. That would be a Bad Thing(tm). Do you have a source for that? I'd be curious. And: Agreed that there are potential advantages to leaving the element there.
T.J. Crowder
*"If neither attribute is present, then the script is fetched and executed immediately, before the user agent continues parsing the page."* - http://dev.w3.org/html5/spec/semantics.html#script And although that link is to the HTML5 spec, I'm sure this isn't a new behavior/requirement.
T.J. Crowder