Detailed answer
For external classic scripts, defer allows parsing to continue and runs after parsing while preserving order among deferred scripts.
Async runs when ready without preserving dependency order. Choose based on whether code needs other scripts or the completed DOM. Module scripts have their own default loading behavior.
Example
<script src="/scripts/menu.js" defer></script>
<script src="/scripts/independent-widget.js" async></script>
Understanding the behavior
For external classic scripts, defer downloads without blocking parsing and executes after parsing in document order. Async runs when available and does not preserve dependency order. Inline classic scripts do not gain deferred execution just by adding defer.
Practical implementation notes
If one script depends on another, preserve a reliable loading order or use a module dependency graph. Inspect the first console error rather than assuming every missing interaction is a download failure.
How to check it
Use a loading strategy that preserves the dependency order and test under slow network conditions.
Expected result
Deferred classic scripts run after parsing in their document order.
Watch out: Do not mark order-dependent classic scripts async and expect source-order execution.
Read the reference ↗