In the last article, in case you missed it, we’ve written about the procedure of parsing the HTML inside the browser. I mentioned there that the browser will stop parsing the document if it comes across <script>...</script>
or <script src=" ">...</script>
tags. The browser stops parsing the page and starts executing the script immediately (if the script is external). Then the browser will download the script, execute the script, and only then continue the initial work.
This poses a question. What if for some reason, we don’t have access to a particularly fast internet connection, and if we try to download a huge HTML file with a lot of nested script objects? This can have a huge impact on the loading time of our webpage. The page itself would be blank and the user experience would be forever ruined. Ok, maybe not, but it would definitely be quite annoying! :D.
Put your script tags at the bottom
The first lesson to learn is to never put script tags inside the <head>
elements.
<!doctype html>defer <html> <head> <title>Example Domain</title> <script src="script.js"></script> <style type="text/css"> </style> </head> <body> <div> ... </div> </body> </html>
The page would be blocked for a long time! Additionally, by blocking the parsing of the HTML, the script can’t interact with the DOM!).
So we put our <script>...</script>
tags right before we close our body tag, as shown in the following listing:
<!doctype html>defer <html> <head> <title>Example Domain</title> <style type="text/css"> </style> </head> <body> <div> ... </div> <script src="script.js"></script> </body> </html>
Async And Defer
Defer
But if we use newer browsers (and almost all modern browsers have async
and defer
included as part of the browser’s documentation), we can asynchronously retrieve the accompanying JavaScript logic, and let the browser parse HTML without any interruptions!
First thing first, for async
and defer
to actually work we need to put our <script>
tag inside the <head>
tag. So, we actually go back to the things I’ve said not to do 🙂
Using defer
we tell the browser to continue parsing the HTML, and let the script download in the background. The script will run once it’s fully downloaded:
<!doctype html>defer <html> <head> <title>Example Domain</title> <script defer src="script.js"></script> <style type="text/css"> </style> </head> <body> <div> ... </div> </body> </html>
Deferred scripts will never block the parsing of the HTML, and will execute once the DOM
is ready (it will wait for the DOMContentLoaded
event, that is – when the HTML document has been completely loaded and parsed). A thing to note regarding deferred scripts is that they keep their relative order, that is:
... <script defer src="https://somesource.com/script1.js"></script> <script defer src="https://somesource.com/script2.js"></script> <script defer src="https://somesource.com/script3.js"></script> ...
The browser will actually download the scripts in parallel, but it will wait until all the scripts are downloaded and will only then run all the scrips in the order they are written, the script1.js
first, then the script2.js
and finally the script3.js
.
Async
Async
is also non-blocking, but it differs in a couple of important points. If a script has the async
attribute, it doesn’t wait for other scripts (for comparison, defer
waits), and the async script will load immediately when ready, not caring for anything else (even the DOMContentLoaded
event).
... <script async src="https://somesource.com/script1.js"></script> <script async src="https://somesource.com/script2.js"></script> <script async src="https://somesource.com/script3.js"></script> ...
Whichever one of those three scripts loads first the browser will run, and they don’t care whether the document has been fully downloaded.
Final Words
Because neither async
nor defer
block the initialization of the webpage, the webpage might be incomplete or still building. In this case, we should (in order to follow good UX practice) always help the user by showing a loader or any other indicator that the page is still not fully interactable.
For more articles please click below, or check the blog.
- Largest Palindrome Product
- Largest Prime Factor
- Even Fibonacci Numbers
- Multiples of 3 or 5
- How to find the missing number in a given integer array of 1 to 100?
- Understanding Javascript prototypes
- Difference between Promise.all() and Promise.race()
- JavaScript generators
- Using this and arguments
- Arrow functions in JavaScript