Keywords: JavaScript execution timing | HTML parsing | script loading optimization | defer attribute | modular scripts
Abstract: This article provides an in-depth exploration of JavaScript execution timing during HTML page parsing, analyzing the default synchronous execution mechanism and its impact on page rendering. Through comparative analysis of traditional script tags, modular scripts, and the defer and async attributes, it systematically explains how to control script execution order for optimal page performance. With practical code examples demonstrating DOM manipulation effects under different loading strategies, the article offers valuable best practice guidance for front-end developers.
Fundamental Principles of JavaScript Execution Timing
When a browser encounters a standard <script> tag during HTML document parsing, it immediately pauses HTML parsing and executes the JavaScript code. This synchronous execution mechanism ensures that potential document.write calls within scripts can correctly output markup content for the parser to process. By default, script execution blocks subsequent HTML content parsing and rendering.
Strategies for Delaying Script Execution
JavaScript Modular Approach
Scripts with the type="module" attribute are deferred until HTML parsing completes and the initial DOM is constructed. Modular scripts can be loaded and parsed in parallel with HTML parsing, but their execution is precisely controlled to occur after DOM readiness.
<script type="module" src="./my-code.js"></script>
<!-- Or inline module -->
<script type="module">
// Module code here
</script>This approach is widely supported in modern browsers. For compatibility with older browsers, bundling tools like Webpack and Rollup.js can be employed.
Application of defer Attribute
Adding the defer attribute to traditional script tags achieves similar deferred execution:
<script defer src="./my-code.js"></script>Similar to the modular approach, script loading and parsing occur in parallel with HTML parsing, but execution is postponed until after HTML parsing completes. Note that defer only applies to external script files referenced via src.
Asynchronous Loading with async Attribute
The async attribute allows scripts to execute immediately after loading, without waiting for HTML parsing to complete:
<script async src="./my-code.js"></script>This approach suits independent functional modules that don't rely on complete DOM structure, but may cause dependency issues due to uncertain execution timing.
Script Placement Optimization
Placing <script> tags at the document end, immediately before the </body> tag, represents a classic deferred execution strategy:
<!doctype html>
<html>
<body>
<!-- Page content -->
<script src="./my-code.js"></script>
</body>
</html>Although modern browsers feature prefetching optimizations, modular and defer approaches offer more precise and reliable execution timing control.
Execution Timing Comparison Examples
Synchronous Execution Example
The following code demonstrates default synchronous execution behavior:
<style>
.found { color: green; }
</style>
<p>First paragraph</p>
<script>
document.querySelectorAll("p").forEach(p => {
p.classList.add("found");
});
</script>
<p>Second paragraph</p>Execution results show only the first paragraph marked green, as the second paragraph hasn't been parsed when the script executes.
Deferred Execution Example
The same functionality using modular scripts:
<style>
.found { color: green; }
</style>
<p>First paragraph</p>
<script type="module">
document.querySelectorAll("p").forEach(p => {
p.classList.add("found");
});
</script>
<p>Second paragraph</p>Both paragraphs are correctly marked, proving script execution occurs after complete DOM construction.
Performance Optimization Considerations
In modern web development, the DOMContentLoaded event and traditional "ready" functionality libraries are no longer necessary choices. Modular and defer approaches provide more elegant solutions that ensure script execution at appropriate times while fully utilizing browser parallel loading capabilities.
For scenarios requiring waiting until all resources (such as images) are fully loaded, the window.onload event still holds value, but its late triggering timing may impact user experience. In practical applications, trade-offs between different approaches should be weighed according to specific requirements.