The Script Tag in Your HTML Document

Bern
The Startup
Published in
11 min readNov 12, 2020

--

Laptop with a working split-screen on coding
Photo by Joshua Aragon on Unsplash

An age old debate among the developers community, like nations of the allied forces and the communists from WWII, still lingers on till today about where is the right place to put the <script> tag that links to your external Javascript file.

A brief intro about the usage of Javascript on the client side context, it is the programming language used by developers to add interactivity to webpages. A few common examples of these interactive features that you might be familiar with most modern websites today are the slider button that changes the theme of a webpage between light & dark mode, a drop down navigation menu bar that contain a list of links on Atlassian webpage, and a fancy error message below the input field when you typed in the wrong password for your Gmail account.

Before I get into more detail about the core of the debate, let’s first examine the process of how a browser loads a website with <script> tag on it…

The Theory Behind It

Step-by-step process as a webpage is being loaded by a browser:

  1. Fetch the HTML page (e.g. index.html)
  2. Begins parsing the HTML
  3. The parser encounters a <script> tag referencing an external script file.
  4. The browser requests the script file. Meanwhile, the parser blocks and stops parsing the other HTML on your page.
  5. After some time, the script is downloaded and subsequently executed.
  6. The parser continues parsing the rest of the HTML document.

Note: The parser will stop whenever it encounters a <script> tag anywhere in the HTML document, regardless of where it is placed.

One of the many features of Javascript as the de facto client side programming language on the web browser is that they are able to insert their own HTML into the Document Object Model (DOM) or other DOM-related manipulations. This also means that the parser normally has to wait until the entire script file has been completely downloaded and executed on the browser before it will continue parsing the rest of the HTML document. For a more comprehensive view on what a Document Object Model (DOM) is, you can refer to this beginner-friendly developer documentation.

The convention these days with Javascript developers is to wait until the entire document has been loaded before modifying it. For example, the browser doesn’t know that whether your script.js file is going to modify anything on the document until it has fully download and executed, therefore this stops the parser from continuing parsing the rest of the HTML document.

Ye Good Olde Days

An antique Corona typewriter sitting on a wooden table.
Photo by Patrick Fore on Unsplash

To solve this problem, Javascript developers came up with the solution of simply positioning the <script> tag at the bottom of the <body> tag like so:

script tags at the bottom of the a HTML body tag
Image provided by the author

Now this might solved the problem of preventing the parser from parsing the rest of the document, however this old approach comes with its own problem. As the parser goes through a synchronous order (top to bottom) of parsing the document, the browser wouldn’t be able to start downloading the scripts until the entire document is parsed all the way to the bottom of the <body> tag. At a glance, this might not seem like a big deal and its not, especially for mores static websites that doesn’t have a lot of interactive features.

However, for larger websites that utilizes a lot of modern and fancy features in both styling and interactivity, they would contain multiple large scripts and stylesheets files and being able the download and execute them as soon as possible is extremely important for performance and user experience. With the availability to high internet bandwidth globally, users expectations have also evolved accordingly and this created a new general norm for a good user experience online. When a website doesn’t load within 2–3 seconds, this is considered a bad user experience and impression on the website itself.

For example, if you’re running an e-commerce website and users encounter this problem when trying to access your webpage, they’ll unlikely stick around to wait for your webpage to load up but rather move on to another website that is your competitor. If a 100 or 1000s of customers encounter the same problem with your website, this could cost a huge profit loss and in return affect your business on a larger scale. Not to mention, the compilation of bad reviews on your website would even deter prospective first-time visitors to your site.

Great, so we now know how big of a deal this could turn out to be and it looks like in a ideal world, the browser would be able to do two things at the same time; starts downloading the scripts as soon as possible, while at the same time continues parsing the rest of your document. How in God’s name do we do that, you say? Well, luckily with the improvements made by the good folks at ECMA, we now have access to two new boolean attributes since the ES6 version of Javascript!

To ASYNC or to DEFER

A modern thin bezel tablet with pictures of models
Photo by XPS on Unsplash

With the new version of ES6 JavaScript, the async and defer attributes were introduced as part of the many new features that came along with this major update. Let’s take a look at async first.

ASYNC

Async stands for the “asynchronous”. By definition, it means something or an operation occurring at the same time. If you’re wondering whether the async attribute works the same by definition in Javascript, you couldn’t be more right!

To simply put, <script> tags with the async attribute attached are dowloaded and executed at the same time, without blocking the parser from parsing the rest of the document. If you have multiple <script> tags in your HTML, this also means that both scripts will be downloaded and executed simultaneously. Depending on the size of each script, the smaller one will always be ahead in terms of loading and execution. Take a look at this example:

Multiple script tags with async attributes
Image provided by the author

Using the figure above as an example, we have 2 script tags that links to 2 external Javascript files name client.js and client2.js . Both of these script tags has an async attribute attached to them so that means both scripts will be download and executed at the same time. Think of it as a race, if client2.js contains a smaller script, it will be downloaded much faster and therefore executed first before the client.js script. What’s the implication on this method, whether it is something a website can benefit always from, depends on how the website functionality and interactive features are structured in their code. In this instance, it could either “make or break” your website. Consider the following scenario:

If your script file finishes downloading and executed before your HTML document is done parsing, certain functionality and features of your website could end up not working properly as your Javascript code wouldn’t be able to find that link between your HTML document that makes that functionality to work on your website.

Say you have input field with a class name "user-input" and in your Javascript code you have a "querySelector()" that looks for that class name, like so: const userInputField = document.querySelector('user-input'); . If your script were to be executed before the parsing of the HTML document reaches the part where you have the input field with that class name, your Javascript won’t be able to find that link and therefore whatever features you’ve implemented with your code that ties to that input field it would not work properly anymore.

For this reason, sometimes Javascript developers would look towards implementing the other option which is the defer attribute.

DEFER

As the word implies, defer by definition means “to delay” or “do it later”. Again, does the attribute works the same way as it is defined? Ya’ damn right it does!

Scripts with the defer attribute are executed in order and this also does not block the browser from parsing the rest of the HTML document. Lets take a look:

Multiple script tags with the defer attribute
Image provided by the author

In the figure above, you can see 2 script tags with its defer attribute attached. In terms of the actual code, there’s nothing special on how you write them to async besides just changing it to the defer attribute in place of async. The main difference here with async scripts, is how they actually work behind the scenes and that defer scripts are only executed after the entire document has been parsed. This means the scripts will be downloaded first as usual while the document continues to parse, but the actual execution of the scripts will be put on hold until the entire HTML document finishes parsing.

To ensure functionality and features of a website to work properly, defer would certainly make for a safer choice. Again, the choice to use async or defer relies upon how the code in the scripts are structured to be implemented and this is something where developers have to decide which would be the best use case for their project in question.

The Debate Itself

A judge’s gavel
Photo by Tingey Injury Law Firm on Unsplash

Before I dive into the core of the debate, a major difference to note in the <script> tag with either the async or defer attributes allow developers to place them within the <head> at the top of the HTML document where stylesheets of the website are normally placed.

Browser Compatibility

Now that’s out of the way, let’s look at why this debate still linger on till today. The first and foremost of this has to do with compatibility with the browser program themselves. As developers, one of the main aspect to take into consideration when building out any website or app is to ensure that user gets a good experience from using our product. There are many aspects to ensure this is delivered when we shipped any of your product for public use, but the main aspect in question here is browser compatibility.

According to canisue.com, browser compatibility with async rates at 98.34% and defer rates at 98.35% across all browsers globally. Specific countries might be rated slightly lower depending on how common a particular browser is used within that country itself. For example, Australia rates the compatibility at 97.04% for the defer attribute. Slightly lower than the global rate but that’s only because the usage of certain browsers are slightly lower comparing to the global rate itself.

To have a better understanding on how the rating works across browsers and individual countries, this is a reliable source page for checking and staying up-to-date with compatibility-related issues. Click here for Defer and here for Async.

As the debate of compatibility on whether to use the new features of async and defer that comes with ES6 JavaScript, some developers prefer not to risk the small percentage gap of 2–3% of users around the world of not being able to fully experience their product but some are not too concern and find it is more worthwhile to embrace the new features that comes with newer version of the JavaScript language.

Legacy Code

The other side of this whole debacle is got to do with something call “legacy code”. Legacy code is the term used in the developers community to describe programs and software that still runs on an older version of programming language. A common example of this we still see today are old websites running on the pre-ES6 version of Javascript (i.e. ES5).

As ES5 and its predecessors version of JavaScript doesn’t come with asynchronous and defer features, using these new ES6 features to work with older versions of code might cause incompatibility issues or inconsistency in the code structure itself. As legacy code are generally harder to maintain and tend to be not very highly interpreted as their successors, using newer features from the new versions of the language might cause some inconsistency and therefore makes it even harder to work with, especially when a developer needs to debug an error in the code.

As a developer, a common example you could find yourself in this situation would be working with government-related websites as they tend to upgrade their software much more slower compare to private businesses due to the amount of bureaucracy involved in the process of such approval.

Personal Verdict

Photo by Avery Evans on Unsplash

For as long as browser compatibility isn’t at least 99% or above and legacy code is still commonly in use at certain governmental departments and old institutions, the debate between which method is more ideal or better practice will go on till the end of time.

My personal take on this; As far as my own limited experience goes as a recent career-changer to the field of software engineering, would be to make yourself adaptable as a developer. With most startups and tech companies, you would normally find they are quite up-to-date with using the latest features and implementing fancier functionalities of the programming languages they use and therefore using newer syntax features like the async and defer attributes for the <script> tags would normally be the convention in these places. As for establishment like older law firms or public libraries, you might find working with legacy code is a more common norm.

As a developer, being fluent in the ES6+ versions of JavaScript is paramount to your success as JavaScript frameworks like React and Vue uses very modern syntax of the Javascript language and these tools are becoming a requirement as an industry standard for a Software Engineer. That being said, competency in the pre-ES6 JavaScript would not only make you appreciate the language itself much more as being able to compare the convenience we have now with the newer features between the old versions, it would also help you achieve a higher understanding of the language and make you a highly demand Javascript developer in the market.

I know this ended up being a very long article over a minor topic which I’m pretty sure it has been covered a many number of times across different websites and on Medium itself, so thank you for taking the time to read any amount of this article.

In the following months as I discover more about being a Software Engineer, I will be writing more articles on any number of things related to software engineering, so do keep an eye out if you’re interested!

--

--

Bern
The Startup

I’m a Software Engineer specializing in iOS apps, and I write blogs about life as a Software Engineer.