文书 發表於 2025-5-16 11:15:00

Web前端入门第 54 问:JavaScript 3 种书写位置及 script 标签的正确存放位置

<p>JS 的代码并没有强制规定放在 HTML 中的某个位置,如果您有使用过开发者工具查看过网页源码,那么您会看到很多 JS 代码都以 <code>.js</code> 文件的形式存放,并且放在了 HTML 文件最后,也就是 <code>&lt;/body&gt;</code> 结束标签之前。</p>
<p>但如果仔细观察,在 <code>&lt;head&gt;</code> 标签中,也会找到很多 script 标签引入的 JS 代码。</p>
<p>那么您是否好奇过他们都有哪些区别??</p>
<h2 id="3-种书写位置">3 种书写位置</h2>
<p>与 CSS 一样,JS 的脚本算起来也有三种书写方式,分别为行间 JS 代码、内联脚本、外部脚本。</p>
<p><strong>1、事件处理</strong></p>
<p>直接在 HTML 元素的事件属性中写代码,此方式一般多用于编写 demo 测试程序,正常的项目开发<strong>不推荐</strong>这种写法。</p>
<p>原因:<code>onclick</code> 中的方法名必须全局声明,导致污染全局变量,并且混合了 HTML 结构和 JS 事件行为代码,不利于项目维护。</p>
<pre><code class="language-html">&lt;p onclick="alert('Hello World!')"&gt;点击我&lt;/p&gt;

&lt;a href="javascript:alert('Hello World!')"&gt;点击我&lt;/a&gt;
</code></pre>
<p><strong>2、内联脚本</strong></p>
<pre><code class="language-html">&lt;script&gt;
console.log('Hello World!')
&lt;/script&gt;
</code></pre>
<p><strong>3、外部脚本</strong></p>
<pre><code class="language-html">&lt;script src="script.js"&gt;&lt;/script&gt;
</code></pre>
<p>ES6 模块化引入,此方式必须要有一个服务器环境!比如:本地安装一个 <code>nginx</code>。</p>
<pre><code class="language-html">&lt;script type="module" src="module.js"&gt;&lt;/script&gt;
</code></pre>
<h3 id="内联脚本应用场景">内联脚本应用场景</h3>
<p>内联脚本一般多用于页面初始化、临时代码调试、首屏渲染必需的初始化逻辑等场景,比如三方插件初始化:</p>
<pre><code class="language-html">&lt;script src="https://cdn.bootcdn.net/ajax/libs/vConsole/3.15.1/vconsole.min.js"&gt;&lt;/script&gt;
&lt;script&gt;
new VConsole();
&lt;/script&gt;
</code></pre>
<h3 id="外部脚本应用场景">外部脚本应用场景</h3>
<p>外部脚本适合复杂、复用性高的场景,是现代 Web 开发的主流选择,使用外部脚本可以降低 HTML 代码的复杂度,有利于项目的维护。</p>
<pre><code class="language-html">&lt;!-- 所有页面引入公共工具代码 --&gt;
&lt;script src="utils.js"&gt;&lt;/script&gt;
&lt;!-- 所有页面引入公共代码 --&gt;
&lt;script src="common.js"&gt;&lt;/script&gt;
&lt;!-- 页面独立的 JS 代码 --&gt;
&lt;script src="index.js"&gt;&lt;/script&gt;
</code></pre>
<p><strong>模块化引入方式:</strong></p>
<pre><code class="language-html">&lt;script type="module" src="index.js"&gt;&lt;/script&gt;
</code></pre>
<p>index.js:</p>
<pre><code class="language-js">import { a } from './utils.js';
import { b } from './common.js';
a();
b();

document.querySelect('#button').addEventListener("click", async () =&gt; {
// 按需加载模块
const module = await import("./test-module.js"); // test-module.js 中导出 run 方法
module.run();
console.log('Hello World!');
});
</code></pre>
<h2 id="script-标签属性">script 标签属性</h2>
<p>script 标签除了常见的 type 和 src 外,还有两个控制脚本异步加载的属性,分别为 async 和 defer,区别如下:</p>
<h3 id="1无-asyncdefer">1、无 async/defer</h3>
<pre><code class="language-plaintext">HTML 解析 → 遇到 &lt;script&gt; → 停止解析 → 下载脚本 → 执行脚本 → 继续解析 HTML
</code></pre>
<h3 id="2async">2、async</h3>
<pre><code class="language-plaintext">HTML 解析(并行下载脚本) → 脚本下载完成 → 立即执行(可能中断 HTML 解析)
</code></pre>
<p>有多个 async 无法保证执行顺序,谁先下载完、谁先执行,所以 async 不适合于依赖顺序的脚本。脚本执行可能发生在 DOMContentLoaded 事件之前或之后,取决于下载速度。</p>
<pre><code class="language-html">&lt;!-- 无法保证执行顺序,谁先下载完谁先执行 --&gt;
&lt;script async src="script1.js"&gt;&lt;/script&gt;
&lt;script async src="script2.js"&gt;&lt;/script&gt;
</code></pre>
<p>应用场景:脚本完全独立,不依赖其他脚本或 DOM,比如:统计代码、广告代码等。</p>
<h3 id="3defer">3、defer</h3>
<pre><code class="language-plaintext">HTML 解析(并行下载脚本) → HTML 解析完成 → 按顺序执行所有 `defer` 脚本
</code></pre>
<p>多个 defer 脚本严格按文档顺序执行,无论下载速度。所有 defer 脚本执行完毕后,才会触发 DOMContentLoaded 事件。</p>
<pre><code class="language-html">&lt;!-- script1.js 一定在 script2.js 前执行。 --&gt;
&lt;script defer src="script1.js"&gt;&lt;/script&gt;
&lt;script defer src="script2.js"&gt;&lt;/script&gt;
</code></pre>
<p>应用场景:脚本需要访问完整的 DOM 或依赖其他脚本,比如:页面初始化逻辑。</p>
<h2 id="script-标签位置">script 标签位置</h2>
<ol>
<li>
<p>首先要明白,存放在 head 中的 script 标签,会阻塞页面加载,如果这个文件超大,那么页面白屏时间就会很长。</p>
</li>
<li>
<p>如果是内联脚本,放在哪儿其实影响不大,主要看其内容中有没有耗时的操作。</p>
</li>
<li>
<p>如果您的脚本需要尽早执行,那么建议放在 head 中。比如:vconsole调试工具,尽早加载有利于捕获代码错误。</p>
</li>
<li>
<p>如果您的脚本需要访问完整的 DOM,那么建议放在 body 的最后,这样可以确保 DOM 已解析完成。</p>
</li>
<li>
<p>虽然可以使用 defer 控制脚本延迟加载,但某些兼容原因,还是建议 JS 脚本后置兼容旧版本浏览器。</p>
</li>
</ol>
<h2 id="写在最后">写在最后</h2>
<p>JS 代码应该首先考虑放在外部文件中,HTML 结构应该永远保持简洁。</p>
<p>除非您真的有需求,才建议将 JS 代码放在 head 中,否则 JS 代码应该永远放在 <code>&lt;/body&gt;</code> 结束标签之前。</p>


</div>
<div id="MySignature" role="contentinfo">
    <p>&nbsp;</p>
<p style="font-size: 18px;font-weight: bold;">文章首发于微信公众号【<span style="color:rgb(255, 71, 87)">前端路引</span>】,欢迎 <span style="color:#4ec259">微信扫一扫</span> 查看更多文章。</p>
<p>
<img style="max-width: 320px;" src="https://images.cnblogs.com/cnblogs_com/linx/2447020/o_250228035031_%E5%85%AC%E4%BC%97%E5%8F%B7%E4%BA%8C%E7%BB%B4%E7%A0%81.png"/>
</p>
<p>本文来自博客园,作者:前端路引,转载请注明原文链接:https://www.cnblogs.com/linx/p/18879715</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/linx/p/18879715
頁: [1]
查看完整版本: Web前端入门第 54 问:JavaScript 3 种书写位置及 script 标签的正确存放位置