
把 <script></script> 放哪儿才不阻塞渲染
浏览器遇到 <script></script> 默认会暂停 HTML 解析,等 JS 下载、执行完才继续——这是首屏慢的常见元凶。
关键不是“要不要放底部”,而是“要不要阻塞解析”:
- 内联脚本(
<script>console.log(1)</script>)一定阻塞,除非加defer或async - 外部脚本加
defer:下载不阻塞,执行在 DOM 解析完成后、DOMContentLoaded前,顺序保证 - 外部脚本加
async:下载不阻塞,下载完立刻执行,不保证顺序,适合统计、广告等独立逻辑 -
<script src="a.js" defer></script>和<script src="b.js" defer></script>会按书写顺序执行;async不保证
别在 里写没加 defer/async 的外部 <script></script>,尤其别放 CSS 加载前——这会让 CSSOM 构建卡住,进一步拖慢渲染。
CSS 放 但别塞太多 @import
<link rel="stylesheet"> 在 是对的,但用 @import 引入其他 CSS 文件会触发串行加载,破坏并行下载能力。
立即学习“前端免费学习笔记(深入)”;
比如:main.css 里写 @import "reset.css"; @import "layout.css";,浏览器必须先下载 main.css,再逐个请求被 import 的文件,无法并发。
- 用
<link>并行引入:多个<link rel="stylesheet">会并行下载 - 避免在 CSS 文件中用
@import,尤其是跨域或深层嵌套时 - 如果必须条件化加载(如主题),优先用 JS 动态
link,而非@import
现代构建工具(如 Vite、Webpack)默认不生成 @import,但手写 CSS 或老项目里仍常见,查一查 grep -r "@import" src/ 就知道有没有踩坑。
用 preload 提前捞关键资源,但别乱用
<link rel="preload"> 是告诉浏览器:“这个资源我马上就要,现在就去下”,但它不改变执行时机,只影响下载优先级。
只对明确已知会立即用到的资源有效,比如首屏字体、关键图片、核心 JS 模块:
-
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>(注意crossorigin,否则字体可能被拒绝使用) -
<link rel="preload" href="hero.jpg" as="image">配合<img alt="如何优化HTML的文档结构_提升网页加载速度的代码组织原则【建议】" >的loading="eager" - 别对所有
<script></script>都preload:它不会推迟执行,反而可能挤占带宽,干扰真正关键的资源 - 不支持
preload的旧浏览器直接忽略,无副作用,但别指望它解决兼容性问题
判断是否该 preload 的简单标准:这个资源是否在 DOMContentLoaded 前就必须就位?如果不是,大概率不需要。
HTML 本身别搞“动态拼接”,服务端能定的尽量定死
所谓“提升加载速度”,很多时候败在 HTML 生成阶段:模板引擎边渲染边请求数据、JS 拼 DOM、甚至用 document.write 插入 script —— 这些都会打断流式解析,让浏览器反复重排解析器状态。
- 服务端渲染(SSR)输出完整 HTML,比客户端渲染(CSR)首屏快一个网络往返
- 避免在
里用 JS 注入<meta>或<link>,这些标签必须在初始 HTML 流中出现才生效 - 不要用 JS 动态写
<script src="..."></script>来“优化加载时机”,不如用defer或async控制原生行为 - 检查 Chrome DevTools 的 “Coverage” 面板,看 HTML 文件里有没有大量未使用的内联 JS/CSS,它们白白增大了传输体积
最易被忽略的一点:HTML 文件本身 gzip 后超过 15KB,就可能因 TCP 慢启动多耗一个 RTT。压缩、删空格、移除无用注释,比纠结某个 async 属性更实在。









