{
    "slug": "script_loading",
    "term": "Script Loading (defer, async, type=module)",
    "category": "frontend",
    "difficulty": "intermediate",
    "short": "How and when browser downloads and executes JavaScript — defer, async, and type=module control whether scripts block HTML parsing and in what order they run.",
    "long": "By default, a <script src='...'> in <head> pauses HTML parsing until the script downloads and executes — blocking the entire render pipeline. Three attributes change this: async downloads in parallel and executes immediately when ready (order not guaranteed); defer downloads in parallel and executes after HTML is fully parsed, in source order; type='module' is deferred by default, scoped to the module, and supports static import/export. The rule of thumb: defer for app scripts that need the DOM or depend on each other, async for fully independent scripts like analytics. Inline scripts ignore both attributes — they always block. Placing scripts at the end of <body> is the old workaround; defer is the modern equivalent with better performance characteristics.",
    "aliases": [
        "defer script",
        "async script",
        "script defer",
        "script async",
        "render blocking script",
        "javascript loading strategy"
    ],
    "tags": [
        "frontend",
        "performance",
        "javascript",
        "web-vitals",
        "html"
    ],
    "misconception": "async and defer are interchangeable — async executes as soon as downloaded, breaking execution order for dependent scripts; defer preserves source order and runs after DOM parsing, making it safe for scripts that depend on each other.",
    "why_it_matters": "A single render-blocking script in <head> delays First Contentful Paint by the full download and parse time of that script — on a slow connection this is hundreds of milliseconds of blank page before any content appears.",
    "common_mistakes": [
        "<script> in <head> without defer or async — blocks HTML parsing and delays render.",
        "Using async on scripts that depend on each other (jQuery then a jQuery plugin) — causes intermittent race condition failures.",
        "defer or async on inline scripts — both attributes are silently ignored; inline scripts always block.",
        "Not adding type='module' to ES module scripts — modules are deferred by default and enable import/export and tree-shaking."
    ],
    "when_to_use": [
        "Use defer for any script that needs the DOM or has dependencies on other scripts.",
        "Use async for analytics, ads, or chat widgets that are fully self-contained.",
        "Use type='module' for ES module-based projects to get deferred execution and import/export support."
    ],
    "avoid_when": [
        "Do not use async on scripts that depend on other async scripts — execution order is not guaranteed.",
        "Do not add defer or async to inline scripts — they are ignored and the script will still block."
    ],
    "related": [
        "render_blocking_resources",
        "web_vitals",
        "content_security_policy",
        "resource_hints"
    ],
    "prerequisites": [],
    "refs": [
        "https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script",
        "https://web.dev/articles/efficiently-load-third-party-javascript",
        "https://v8.dev/features/modules"
    ],
    "bad_code": "<!-- Blocks render — browser stops parsing HTML until jQuery downloads and runs -->\n<head>\n  <script src=\"jquery.js\"></script>\n  <script src=\"app.js\"></script>\n</head>",
    "good_code": "<!-- defer: parallel download, executes in order after DOM ready -->\n<head>\n  <script src=\"jquery.js\" defer></script>\n  <script src=\"app.js\" defer></script>\n</head>\n\n<!-- async: only for fully independent scripts with no dependencies -->\n<script src=\"analytics.js\" async></script>\n\n<!-- type=module: deferred, scoped, supports import/export -->\n<script type=\"module\" src=\"app.mjs\"></script>",
    "quick_fix": "Add defer to all app scripts in <head>; use async only for independent analytics/tracking scripts; never leave bare <script src='...'> in <head>",
    "severity": "high",
    "effort": "low",
    "created": "2026-04-06",
    "updated": "2026-04-06",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/script_loading",
        "html_url": "https://codeclaritylab.com/glossary/script_loading",
        "json_url": "https://codeclaritylab.com/glossary/script_loading.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[Script Loading (defer, async, type=module)](https://codeclaritylab.com/glossary/script_loading) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/script_loading"
            }
        }
    }
}