
One of the simplest ways to get your JavaScript running is to just slap it right into your HTML file. This is particularly useful for small projects or quick prototypes. You can embed your scripts directly within the <script> tags in your HTML. Here’s a basic example:
<!DOCTYPE html>
<html>
<head>
<title>Simple Script Example</title>
</head>
<body>
<h1>Hello World</h1>
<script>
function showMessage() {
alert("Welcome to my website!");
}
showMessage();
</script>
</body>
</html>
In this example, as soon as the browser processes the <code><script></code> tag, it runs the showMessage function, which displays an alert. This is great for quick tests, but as your project grows, you might start to feel the pain of having your JavaScript mixed in with your HTML.
One of the downsides of this approach is that it can make your HTML messy and harder to maintain. If your JavaScript grows complex, you’ll find yourself navigating through a sea of markup just to tweak a single function. It can become a nightmare to debug, especially if you’re trying to figure out which script is causing an issue. Also, when you load your HTML file, the browser has to process the JavaScript before it can render the rest of the page, which can lead to slower load times.
As you scale up and start adding more features, you might want to think about organizing your code better. This leads to the next logical step-
Penlike Pencil for Apple iPad A16 10th, Fast Charge Stylus Pen for 2026-2018 iPad A16/11-6th, Air 11"/13" M4/M3/M2/5th-3rd, Pro 13/11/M4/12.9, Mini A17 Pro/6/5th Palm Rejection Tilt Sensitivity
$9.99 (as of June 15, 2026 00:54 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)The grown-up approach putting your code in a separate file
creating a separate JavaScript file. By moving your code into its own file, you can keep your HTML clean and focused on structure and content. This separation of concerns is a fundamental principle of good software development. Here’s how you can do it:
<!DOCTYPE html> <html> <head> <title>External Script Example</title> <script src="script.js"></script> </head> <body> <h1>Hello World</h1> </body> </html>
In this example, the JavaScript code would reside in a separate file named script.js. You’d include it in your HTML with the <code><script src="script.js"></code> tag. Here’s what the script.js file might look like:
function showMessage() {
alert("Welcome to my website!");
}
showMessage();
This way, your HTML remains uncluttered, and all your JavaScript is contained in one place. This makes it significantly easier to manage and debug. If you need to make changes to your JavaScript, you can do so without diving into the HTML.
Another added benefit is caching. When you serve your JavaScript from an external file, the browser can cache it. This means that when users navigate to another page on your site or return later, the script doesn’t need to be reloaded, which can improve load times and performance.
However, there’s a surprisingly important decision to make regarding where to place that <code><script></code> tag in your HTML. The location can greatly impact page loading behavior and user experience…
A surprisingly important decision where to put that script tag
The browser parses your HTML document from top to bottom. When it hits a <script> tag, it has to stop everything. It pauses parsing the HTML, downloads the script file (if it’s external), and executes the JavaScript code. Only after all that is finished does it resume parsing the rest of your page. This is what we call “render-blocking.” If your script is large, or the user is on a slow connection, they will be staring at a blank white page until that script is done. The content, even if it’s just simple text, is held hostage by the script tag in your .
<!DOCTYPE html> <html> <head> <title>Render-Blocking Script</title> <!-- BAD: This script blocks the page from rendering --> <script src="heavy-script.js"></script> </head> <body> <h1>My Awesome Content</h1> <p>You won't see this text until heavy-script.js is downloaded and executed.</p> </body> </html>
This is a terrible user experience. The perceived performance of your site plummets. The classic, time-tested solution to this problem is simple: move your script tags. Instead of putting them in the , you put them just before the closing tag. This way, the browser gets to parse and render all of your HTML content first. The user sees your page immediately. The script still gets downloaded and executed, but it happens after the user is already looking at the content.
<!DOCTYPE html> <html> <head> <title>Non-Blocking Script</title> </head> <body> <h1>My Awesome Content</h1> <p>You see this content right away!</p> <!-- GOOD: Script loads after the content is visible --> <script src="heavy-script.js"></script> </body> </html>
This approach not only improves perceived load time but also solves a common bug. If your script in the tries to manipulate a DOM element, like document.getElementById('my-button'), it will fail with an error because the browser hasn’t parsed that part of the HTML yet; the element doesn’t exist. By placing the script at the end of the body, you guarantee that all the HTML elements are available in the DOM when your script runs.
But wait, there’s more. We live in the future now. HTML5 gave us two powerful attributes for the <script> tag that give us finer control: defer and async. These let you keep your scripts in the without blocking rendering. The defer attribute tells the browser to download the script in the background while it continues parsing the HTML. The script will only be executed after the HTML parsing is complete, right before the DOMContentLoaded event. Crucially, if you have multiple deferred scripts, they will execute in the order they appear in the document.
<!DOCTYPE html> <html> <head> <title>Using defer</title> <!-- BEST: Non-blocking, and executes after parsing, in order. --> <script src="jquery.js" defer></script> <script src="my-app-logic.js" defer></script> </head> <body> <!-- Content renders immediately --> <h1>Content First!</h1> </body> </html>
For most of your application scripts, defer is exactly what you want. It combines the best of both worlds: the browser discovers the script early and can start downloading it sooner, but it doesn’t block rendering, and you get a predictable execution order. Then there’s async. This attribute also tells the browser to download the script in the background without blocking. However, the moment the script finishes downloading, the browser will pause HTML parsing to execute it. This means async scripts can execute in any order, depending on which one finishes downloading first. This is useful for self-contained, third-party scripts that don’t depend on your other code or the DOM, like an analytics tracker or an ad script.
<!DOCTYPE html> <html> <head> <title>Using async</title> <!-- Your main script, deferred for predictable execution --> <script src="app.js" defer></script> <!-- Independent third-party script that can run whenever --> <script src="https://analytics.example.com/tracker.js" async></script> </head> <body> <h1>More Content!</h1> </body> </html>
So, the modern pecking order is generally: use defer for your application scripts placed in the . Use async for independent third-party scripts. And if you need to support very old browsers that don’t understand these attributes, the classic technique of placing your <script> tags at the end of the is still a perfectly valid and robust strategy.
