# async vs defer in JavaScript: How Script Loading Really Works

# How Script Loading Really Works

If you’ve ever added JavaScript to an HTML page, you’ve probably written something like this:

```javascript
<script src="script.js"></script>
```

But modern JavaScript gives you two powerful attributes:

* `async`
    
* `defer`
    

They **change how scripts load and execute**, and using the wrong one can break your page.

In this article, you’ll learn:

* how browsers load scripts by default
    
* what `async` does
    
* what `defer` does
    
* key differences between them
    
* when to use each
    
* common mistakes
    

Let’s start with the default behavior.

---

## How Browsers Load JavaScript by Default

When the browser encounters this:

```javascript
<script src="app.js"></script>
```

It does **three things in order**:

1. Stops parsing HTML
    
2. Downloads the JavaScript file
    
3. Executes the JavaScript
    
4. Resumes parsing HTML
    

This is called **render-blocking**.

### Problem with Default Behavior

* Slows down page rendering
    
* Bad for performance
    
* Especially harmful for large scripts
    

This is where `async` and `defer` help.

---

# What Is `async`?

The `async` attribute tells the browser:

> “Download this script in parallel, and execute it **as soon as it’s ready**.”

```javascript
<script src="async.js" async></script>
```

---

## How `async` Works

1. HTML parsing continues
    
2. Script downloads in parallel
    
3. HTML parsing **pauses** when the script finishes downloading
    
4. Script executes immediately
    

Execution time is **not predictable**.

---

## Example

```javascript
<script src="analytics.js" async></script>
```

This is perfect for scripts that:

* do not depend on DOM
    
* do not depend on other scripts
    

---

## Key Characteristics of `async`

✔ Downloads in parallel  
✔ Executes immediately after download  
❌ Execution order not guaranteed  
❌ Can interrupt HTML parsing

---

# What Is `defer`?

The `defer` attribute tells the browser:

> “Download this script in parallel, but execute it **after HTML parsing is complete**.”

```javascript
<script src="defer.js" defer></script>
```

---

## How `defer` Works

1. HTML parsing continues
    
2. Script downloads in parallel
    
3. Script execution waits
    
4. Executes **after DOM is fully built**
    

---

## Example

```javascript
<script src="main.js" defer></script>
```

This is ideal for scripts that:

* manipulate the DOM
    
* depend on HTML elements
    

---

## Key Characteristics of `defer`

✔ Downloads in parallel  
✔ Executes after HTML parsing  
✔ Execution order is preserved  
✔ Safe for DOM access

---

# `async` vs `defer`: Side-by-Side Comparison

| Feature | `async` | `defer` |
| --- | --- | --- |
| HTML parsing | Pauses during execution | Never pauses |
| Download | Parallel | Parallel |
| Execution time | As soon as ready | After DOM loaded |
| Order preserved | ❌ No | ✔ Yes |
| DOM safe | ❌ Not guaranteed | ✔ Yes |
| Best for | Independent scripts | App logic |

---

# Execution Order Example

```javascript
<script src="a.js" async></script>
<script src="b.js" async></script>
```

Execution order:

* `a.js` or `b.js` (depends on download speed)
    

---

```javascript
<script src="a.js" defer></script>
<script src="b.js" defer></script>
```

Execution order:

1. `a.js`
    
2. `b.js`
    

Always in order.

---

# When Should You Use `async`?

Use `async` when the script:

✔ Is independent  
✔ Does not access DOM  
✔ Does not depend on other scripts

### Common Use Cases

* Analytics
    
* Ads
    
* Tracking scripts
    

```javascript
<script src="google-analytics.js" async></script>
```

---

# When Should You Use `defer`?

Use `defer` when the script:

✔ Needs DOM access  
✔ Depends on other scripts  
✔ Is part of your application logic

### Common Use Cases

* Main JS files
    
* UI logic
    
* Event handlers
    

```javascript
<script src="app.js" defer></script>
```

---

# What About Scripts at the Bottom of `<body>`?

Old approach:

```javascript
<script src="app.js"></script>
</body>
```

Modern approach:

```javascript
<script src="app.js" defer></script>
```

✔ Cleaner  
✔ Better performance  
✔ Recommended

---

# `async` and `defer` with Inline Scripts

They **do not work** with inline scripts.

❌ This does nothing:

```javascript
<script async>
  console.log("Hello");
</script>
```

They only work with external scripts.

---

# Common Mistakes

### ❌ Using `async` for dependent scripts

```javascript
<script src="lib.js" async></script>
<script src="app.js" async></script>
```

`app.js` may run before `lib.js`.

---

### ❌ Accessing DOM with `async`

```javascript
document.getElementById("btn"); // may be null
```

---

### ❌ Mixing async and defer carelessly

Stick to one strategy.

---

# Best Practices

✔ Use `defer` for most scripts  
✔ Use `async` only when truly independent  
✔ Avoid default blocking scripts  
✔ Never rely on async execution order  
✔ Prefer `defer` over placing scripts at bottom

---

# Mental Model to Remember

* **Default**: Stop → Download → Execute
    
* **Async**: Download → Execute ASAP
    
* **Defer**: Download → Wait → Execute after DOM
