Script tags are executed in the order they appear
This idea should be intuitive when you read this code:
<script> var x = 3; </script> <script> alert(x); // Will alert '3'; </script>
It is less intuitive (but no less true) when working with external resources.
<script src="//typekit.com/fj3j1j2.js"></script> <!-- This second script won’t execute until typekit has executed, or timed out --> <script src="//my.site/script.js"></script>
It similarly works for combinations of local and remote scripts.
Functionally this means you can significantly slow down your site if you have slow scripts loading early in the page. It also means scripts which appear later on the page can depend on things scripts which appear earlier have done.
Elements on the page won’t render until all the script tags preceding them have loaded and executed. This means you can do all sorts of crazy things where you tweak the page before it loads, if you’re willing to accept the performance hit.
This doesn’t apply however if you add script tags to the DOM after the page has
begun to load using
document.appendChild or the like. Those tags will load
whenever the browser sees fit, and in no particular order.
When a script tag executes, everything above it in the DOM is available (but not everything below).
<html> <head> <script> // document.head is available // document.body is not! </script> </head> <body> <script> // document.head is available // document.body is available </script> </body> </html>
You can think of the HTML parser as traveling through the document tag by tag,
querySelectorAll, jQuery, etc.) only if
their opening tag appears earlier in the document than your script tag.
One useful corollary of this is that
document.head is virtually always
only available if your script tag appears inside or after the opening
HTML5 has added a couple tools for controlling when scripts execute.
asyncmeans “execute this whenever”. More specifically that means: I don’t care if you execute this after the whole page has loaded, and every other script has executed. It’s very useful for analytics tracking codes, for example, where no other code on the page depends on their execution. Defining a variable or function in
asynccode which the page needs is bad news, as you have no way of knowing when the
asynccode will actually run.
defermeans “wait for the parser to finish to execute this”. It’s roughly equivalent to binding your script to the
DOMContentLoadedevent, or using
jQuery.ready. When the code does run, everything in the DOM will be available for you to use. Unlike
defer’d code will run in the order it appears in the HTML of the page, it is just deferred until after the HTML is fully parsed.
Historically (since Netscape 2), it hasn’t mattered much if you specified
type though, the
browser won’t execute it. This can be cool when you want to define your own
<script type="text/emerald"> make a social network but for cats </script>
The actual execution of that code is then up to you, i.e.:
<script> var codez = document.querySelectorAll('script[type="text/emerald"]'); for (var i=0; i < codez.length; i++) runEmeraldCode(codez[i].innerHTML); </script>
runEmeraldCode function is left as an exercise for the reader.
If you have a perverse desire to, you can also override the default
every script tag on the page using a
<meta http-equiv="Content-Script-Type" content="text/vbscript">
Take a look at A Brief History of Weird Scripting Languages on the Web
for more details on what
types were valid.
integrity attribute is a part of the new Subresource Integrity spec. It
allows you to provide a hash for the contents which a script file should
contain. It’s meant to prevent a nefarious actor from messing with the
contents of a script tag over the wire. In a world with SSL, this is only
really valuable if you’re loading a script from some external source you don’t
If you do choose to use this, you include which hash you are using, and the hash’s value, separated by a hyphen. It looks like this:
<script src="//code.jquery.com/jquery.js" integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"> </script>
I have yet to see it in the wild, but if you know of a site using it, comment below.
crossorigin is a thing too!
It’s not fully standardized yet, but there is a
crossorigin attribute which
is supported by some browsers. The general idea is that the browser doesn’t
like to let you do much with resources loaded from a different ‘origin’ than
the current page. (The origin is defined as the combination of the page’s
protocol, hostname, and port. I.e.
This is to prevent you from, for example, making requests to your competitors
website which cancels any accounts the current user might have (not nice!).
Its connection to script tags is somewhat incidental though. The idea is if
you apply a handler to the
window.onerror event, that handler is provided
with some information about the page and script which you perhaps shouldn’t
have if you’re loading code from an external site. In secure browsers this
info is not included unless you specify
crossorigin isn’t a magical security hack though, what it does is instruct
the browser to undergo the normal CORS access check of making an
request and checking for
It has zero IE support, making it something of a novelty, but there is a
document.currentScript which points to the current script
being executed. It could be super helpful if you want to pull attributes out
of the script tag your embed is included using. Personally I’m pretty glad it
isn’t fully supported as it would make some of the work we do at Eager to
install embed codes somewhat harder.
This is super useless, because it’s only supported on Firefox. It, along with
onbeforescriptexecute allows you to bind an event which will be executed
before and after every script on the page runs, which is pretty cool.
If you’re curious, the event objects include a reference to the script being
executed, and the
before event can cancel the execution by calling
To this day the HTML5 spec includes a rarely seen, previously IE-specific, method of binding code to an event. You are supposed to be able to do this to have a script tag not run until the page’s load event:
<script for="window" event="onload"> alert("Hi!") </script>
I can’t actually make this work on Chrome or Firefox (making them not standards compliant), but there’s a good chance it still works in IE.
young. There was a day however when you couldn’t be sure if a given browser
browser would even know what a
script tag was. And if a browser doesn’t
recognize a tag, it is supposed to render it as a generic inline element,
Fortunately the spec was helpful enough to provide the solution, wrapping your code in something which the unsupporting browser would interpret as an HTML comment:
<script> <!-- to hide script contents from old browsers // You would probably be pasting a ‘rollover’ script // you got from hotscripts.net here // end hiding contents from old browsers --> </script>
Of course, like most things, XHTML made this much worse. XML has a very special
method of escaping content which might contain closing tags and such,
<script> //<![CDATA[ // Is this the right incantation to get this to pass // the XHTML validator? //]]> </script>
With that, your code would be valid XHTML. This wouldn’t have any impact on its functionality, but was incredibly important to your self worth as a web developer.
Browsers also included a helpful method to allow you to tell people who didn’t
<noscript> wraps the
content which should only be rendered if the browser doesn’t support script
<noscript> Please use Internet Explorer 5.5 or above. </noscript> <script> exploitInternetExplorer0Day(); </script>
If you’re observant you’ll realize that
noscript doesn’t accept the
argument, making its interaction with pages which use multiple script
somewhat ambiguous. The actual behavior varied from browser to browser, but
noscript blocks if any
script tag used earlier in the
document used a not-supported
type. This means that it was very possible to
noscripts not appear, while ones lower on the page did.
Script Tags and
Script tags which are dynamically added to the page via the DOM are executed by the browser:
var myScript = document.createElement('script'); myScript.textContent = 'alert("✋")'; document.head.appendChild(myScript);
Script tags which are dynamically added to the page via
innerHTML are not:
document.head.innerHTML += '<script>alert("✋")</script>';
Why this is is not clear, but it is a fun answer to the trivia question “is it possible to have a script tag show up in the Chrome inspector which has not actually ran?” Which, in turn, makes it a great way to prank your coworkers.
Thanks for tuning in! Our next post
document.write and how weird
it is. Subscribe below to get notified when our new blog posts are released.