资源加载✅
浏览器同一时间可以从一个域名下载多少资源,有什么例外吗?
答案
参考 stackoverflow Max parallel HTTP connections in a browser?
| 浏览器 | HTTP/1.1 每域名连接数明 |
|---|---|
| Chrome | 6 |
| Firefox | 6 |
| Safari | 6 |
| Edge | 6 基于Chromium |
| IE11 | 8 已停止支持 |
提示
注意这里是针对 HTTP/1.1 协议的限制。HTTP/2 和 HTTP/3 通过多路复用技术可以在单个连接上并行处理多个请求,因此不受此限制。具体参考 Why just one TCP connection
HTTP/1.1 限制原因
- 服务器负载保护 防止单个客户端占用过多服务器连接
- 网络拥塞控制 避免过多并发连接导致网络堵塞
- TCP 连接开销 每个连接都需要三次握手,资源消耗较大
重要例外情况
<!-- 1. 不同子域名可以突破限制 -->
<link rel="stylesheet" href="https://cdn1.example.com/style.css">
<link rel="stylesheet" href="https://cdn2.example.com/theme.css">
<script src="https://static.example.com/app.js"></script>
<!-- 2. HTTP/2 多路复用 -->
<!-- 同一连接可并行传输多个资源 -->
<link rel="preload" href="/critical.css" as="style">
<link rel="preload" href="/main.js" as="script">
<!-- 3. 内联资源不占用连接 -->
<style>
.critical { color: red; }
</style>
<script>
console.log('inline script');
</script>
实际开发优化策略
- 域名分片 HTTP/1.1 时代通过多个子域名提高并发数
- 资源合并 减少请求数量,如 CSS/JS 文件合并
- HTTP/2 升级 利用多路复用特性,避免域名分片反优化
- 资源优先级 使用
<link rel="preload">控制关键资源加载
延伸阅读
- HTTP/1.1 Connection Management - RFC 7230 连接管理规范
- HTTP/2 Multiplexing - HTTP/2 多路复用机制
- Browser Connection Limits - 浏览器连接限制测试数据
CSS 加载是否阻塞 DOM 解析、渲染和 JavaScript 执行?
答案
详细解释
| 阻塞对象 | 是否阻塞 | 原因说明 |
|---|---|---|
| DOM 解析 | 不阻塞 | HTML 解析不依赖 CSS 属于流式解析 |
| 页面渲染 | 阻塞 | 渲染依赖 CSSOM 构建,会造成阻塞,注意如果资源加载失败浏览器任然会用兜底的样式进行渲染,这个现象叫做 内容样式短暂失效 (FOUC) |
| JavaScript 执行 | 阻塞 | <script> 标签会等待 CSS 加载完成 |
实际开发建议
- 关键 css 内联导入
- 非关键 CSS 异步加载
<link rel="preload" href="non-critical.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
延伸阅读
- 阻塞渲染的 CSS - CSS 加载优化策略
@import 是否会阻塞主线程?
答案
核心概念
@import 不会直接阻塞 JavaScript 主线程的执行,但它会严重阻塞浏览器的关键渲染路径(Critical Rendering Path),并显著破坏页面的加载性能:
- 打破并发加载,形成瀑布流(Waterfall):
- 浏览器内部拥有高效的预加载扫描器(Preload Scanner),能并发快速拉取 HTML 中的多个
<link rel="stylesheet">。 - 而
@import嵌套在 CSS 内部,浏览器只有在下载完当前 CSS 并解析到@import规则时,才能发现并开始发起新文件的网络请求,导致 CSS 资源从“并发下载”退化为“串行下载”。
- 浏览器内部拥有高效的预加载扫描器(Preload Scanner),能并发快速拉取 HTML 中的多个
- 延迟 CSSOM 构建与首屏渲染:
- CSS 属于渲染阻塞资源(Render-blocking)。在所有通过
@import引入的外部样式表下载、解析完成且完整的 CSSOM 构建就绪前,浏览器无法生成渲染树(Render Tree),页面会持续处于白屏状态,恶化 FCP(First Contentful Paint)和 LCP。
- CSS 属于渲染阻塞资源(Render-blocking)。在所有通过
- 可能引发样式闪烁(FOUC):
- 若在老旧浏览器或特定异步条件下未严格阻断,页面可能会先按部分样式渲染,待
@import资源返回后再重新重绘,导致视觉抖动与重排。
- 若在老旧浏览器或特定异步条件下未严格阻断,页面可能会先按部分样式渲染,待
加载模型对比:
[ 并发模式: 多个 <link> ]
HTML 解析 ─────────►
├─► 下载 styleA.css (并发) ───┐
└─► 下载 styleB.css (并发) ───┴─► 构建 CSSOM ──► 绘制首屏
[ 串行模式: CSS 内部 @import ]
HTML 解析 ─────────►
└─► 下载 main.css ────► 解析到 @import ────► 下载 imported.css ────► 构建 CSSOM ──► 绘制首屏 (严重延迟)
工程最佳实践
- 在生产环境中避免直接在 CSS 中书写运行时
@import。 - 构建阶段通过 Sass、Less 或 PostCSS(
postcss-import)将@import静态内联打包为单个样式文件。
延伸阅读
什么是文档的预解析
答案
文档预解析用来解决关键资源串行加载导致的页面渲染延迟,通过预加载技术,实现对核心资源的并行加载,提升页面加载速度。
预加载包含如下类型
| 类型 | 描述 |
|---|---|
| dns-prefetch | 浏览器提前解析域名,减少后续请求的 DNS 查询延迟。通过 <link rel="dns-prefetch"> 标签实现。 |
| preconnect | 浏览器提前建立与服务器的连接,以减少后续请求的延迟。通过 <link rel="preconnect"> 标签实现。 |
| preload | 浏览器在解析 HTML 时,提前加载指定资源(如脚本、样式表、图片等),以便在需要时可以立即使用。通过 <link rel="preload"> 标签实现。 |
| prefetch | 浏览器在空闲时加载可能会用到的资源,以便在需要时可以立即使用。通过 <link rel="prefetch"> 标签实现。 |
延伸阅读
- Preload critical assets to improve loading speed 详细讲解 preload 的使用及配置策略
- Establish network connections early to improve perceived page speed 详细讲解 preconnect 和 dns-prefetch 的使用及配置策略
你如何对网站的文件和资源进行优化?
答案
网站文件和资源优化是前端性能优化的核心,主要从减少请求数量、优化文件大小、加速传输和提升缓存效率四个维度进行。
资源压缩与合并
| 优化类型 | 具体措施 | 工具示例 |
|---|---|---|
| JavaScript | 代码压缩、Tree Shaking、代码分割 | Webpack、Rollup、Terser |
| CSS | 压缩、去重、关键CSS提取 | PurgeCSS、PostCSS、Critical |
| HTML | 压缩空格、注释删除 | HTMLMinifier |
| 图片 | 格式优化、尺寸压缩、懒加载 | WebP、AVIF、ImageOptim |
HTTP 优化策略
<!-- 1. 资源预加载 -->
<link rel="dns-prefetch" href="//cdn.example.com">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preload" href="/critical.css" as="style">
<link rel="prefetch" href="/next-page.js">
<!-- 2. 关键资源优先加载 -->
<style>
/* 关键CSS内联 */
.header { background: #000; }
</style>
<link rel="stylesheet" href="/non-critical.css" media="print"
onload="this.media='all'">
<!-- 3. 脚本优化加载 -->
<script src="/critical.js"></script>
<script src="/non-critical.js" defer></script>
<script src="/analytics.js" async></script>
缓存策略配置
// Service Worker 缓存策略
self.addEventListener('fetch', event => {
if (event.request.destination === 'image') {
// 图片缓存优先策略
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request)
})
)
}
})
// Webpack 文件名哈希
module.exports = {
output: {
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].chunk.js'
}
}
现代优化技术
- HTTP/2 推送 主动推送关键资源,减少往返时间
- 模块联邦 微前端架构下的资源共享
- ESM 动态导入 按需加载模块,减少初始包体积
- WebAssembly 计算密集型任务性能优化
// 动态导入示例
const loadChart = async () => {
const { Chart } = await import('./chart.js')
return new Chart()
}
// 图片懒加载
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target
img.src = img.dataset.src
imageObserver.unobserve(img)
}
})
})
实际开发建议
- 资源监控 使用 Lighthouse、WebPageTest 定期检测性能
- 渐进式优化 优先优化影响 FCP、LCP 的关键资源
- CDN 部署 静态资源使用 CDN 加速全球访问
- 构建优化 配置合理的 chunk splitting 策略
提示
优化顺序:关键资源内联 → 非关键资源延迟 → 长期缓存策略 → 监控调优
延伸阅读
- Web.dev: 优化资源加载 - 全面的性能优化指南
- Webpack: 性能优化 - 构建工具优化策略
- MDN: HTTP 缓存 - 缓存机制详解
什么是资源预热,有哪些手段?
答案
核心概念 资源预热(Resource Warm-up / Pre-warming)是指在用户实际触发交互或页面渲染真正需要某个资源之前,提前进行网络连接建立、域名解析或资源预加载并缓存。其核心目标是将网络往返耗时(RTT)前置化,消灭关键路径上的加载白屏与等待:
- 连接层预热:
dns-prefetch:提前解析跨域资源服务器的 DNS(如 CDN 域名),消除 ~20-120ms 的 DNS 查询时间。preconnect:比 DNS 预解析更进一步,不仅解析 DNS,还提前完成 TCP 三次握手和 TLS 证书协商,消除完整连接建立耗时。
- 资源层预热:
preload:声明当前页面即将使用的高优先级核心资源(如字体包、首屏核心 CSS/JS、LCP 大图),让浏览器跳过发现阶段立即以最高优先级并行拉取。prefetch:声明用户后续极可能访问的页面或资源(如猜测下一个路由),在当前页面渲染完毕、浏览器空闲(idle)时以最低优先级抓取并存入 HTTP 缓存。prerender/ Speculation Rules API:提前在后台完整渲染下一个页面(包括执行 JS、计算布局),当用户点击跳转时实现 0 毫秒秒开。
- 协议与架构层预热:
- 103 Early Hints:在后端服务器生成主 HTML 响应体期间,提前向客户端发送 HTTP 103 状态码和 Link 头,让浏览器在等待主 HTML 期间提前并发下载 CSS 和关键 JS。
- Service Worker Cache:通过离线缓存策略预先将 App Shell、通用图标与 SDK 存入 CacheStorage。
典型代码配置:
<head>
<!-- 1. 连接层预热:提前与 API 服务器建立 TLS 连接 -->
<link rel="preconnect" href="https://api.example.com" crossorigin>
<link rel="dns-prefetch" href="https://cdn.example.com">
<!-- 2. 当前页关键资源预加载:提前加载首屏字体与 LCP 英雄图 -->
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/images/hero.webp" as="image">
<!-- 3. 下一页未来资源预获取:空闲时下载下个路由的分包 -->
<link rel="prefetch" href="/js/detail-page.chunk.js" as="script">
<!-- 4. 现代标准:投机规则 API (Speculation Rules) 进行预渲染 -->
<script type="speculationrules">
{
"prerender": [
{
"source": "list",
"urls": ["/next-article"]
}
]
}
</script>
</head>
面试官视角
- 考查对浏览器网络链路和现代性能标准(如 Speculation Rules / Early Hints)的了解深度。
- 关键区分点:能否清晰对比
preload(当前页必须,强制高优先级)与prefetch(未来页可能用,空闲低优先级)的语义区别。
延伸阅读