资源加载与缓存优化

共 21 题
📑 题目列表 21 题
#
★★★

1. TanStack Router 的 search params 类型 在测试与可维护性的工程价值

TanStack Router 的 search params 类型在测试与可维护性上有哪些工程价值?

  • search params 的 schema 化类型定义
  • 类型安全在测试与重构中的作用
  • URL 状态单一来源的可维护性

TanStack Router 把 search params 定义为 schema(基于 Zod/Valibot 验证):路由的 validateSearch 声明参数结构、默认值与校验规则,TS 类型从 schema 推导(routeSearch 类型),组件与导航 API 使用参数时全量类型推导与校验——非法参数在编译期与运行期双重拦截,消除"URL 字符串魔法"(手写 query、any 类型)导致的拼写错误与结构漂移。

工程价值:测试侧——导航/断言使用类型化参数(构造 URL 与断言 routeSearch 都走同一类型),参数变更时编译错误直接暴露所有引用点,mock 与断言不再出现类型失真;可维护性——search params 成为"URL 状态契约"(单一事实源:类型、校验、默认值、序列化一处定义),路由重构(改名/改结构)由编译器与验证器护航;配合 URL 状态驱动(刷新可恢复、可分享),测试覆盖"URL 状态变化 → UI 更新"的行为链路,状态逻辑可测性显著提升。

考察类型化 URL 状态的工程价值:schema 单一来源、编译期护航、测试与重构的安全网,回答应体现"URL 即状态契约"的思维。

#
★★★

2. HTTP 103 Early Hints 在静态资源预取的工程价值与现代浏览器支持

HTTP 103 Early Hints 在静态资源预取中有哪些工程价值?浏览器支持现状如何?

  • 103 的机制(提前发 Link 头)
  • 对 TTFB/LCP 的收益
  • 浏览器与 CDN 的支持边界

HTTP 103 Early Hints 让服务端在最终响应前先行发送 1xx 状态与 Link 头(如 Link: </app.css>; rel=preload),浏览器提前发现并下载关键资源,与主响应(HTML)并行进行——相比"等 HTML 到达再发现资源"(串行),把关键 CSS/JS/图片的下载提前一个 RTT,直接改善 LCP(尤其首屏依赖大资源、服务端生成 HTML 较慢的场景)。实现位置:CDN 边缘(命中缓存规则时边缘直接回 103)或应用服务(页面逻辑慢时先发 103)。

支持现状:Chrome/Edge 与 Firefox 已支持(Chromium 从 M103 起,Firefox 108+),Safari 支持有限(历史版本对 103 支持不完整/有回归,WebKit 状态需持续跟踪);CDN 侧需开启功能(Cloudflare、Fastly 等支持)。工程要点:103 资源要"值得提前"(关键路径且最终响应确实引用,避免预取浪费);与服务端渲染耗时成正比收益;降级安全(不支持时只是回到串行,无功能损失);配合 fetchpriority 与 preload 分层,监测 LCP 实际收益。

考察 103 的机制与收益:提前资源发现、并行下载缩短 LCP,回答应包含支持矩阵与降级安全性的工程判断。

#
★★★

3. CDN Cache-Control: stale-while-revalidate 在 HTML/Asset 不同策略的工程取舍

CDN 的 Cache-Control: stale-while-revalidate 在 HTML 与 Asset 上应如何差异化配置?

  • stale-while-revalidate 的机制(过期后异步回源)
  • HTML 与静态资源的新鲜度差异
  • 不同资产的策略组合

stale-while-revalidate(SWR)允许缓存内容过期后先返回旧值(stale)满足当前请求,同时异步回源更新缓存:响应头 Cache-Control: max-age=60, stale-while-revalidate=3600,用户在 1 小时窗口内始终秒回,后台悄悄刷新。HTML 与 Asset 的差异:HTML 承载内容新鲜度(页面更新、配置、权限)——SWR 窗口宜短(分钟级)、结合服务端版本号/ETag 协商,避免用户看到过期内容;静态资产(JS/CSS/图片)内容不可变(hash 文件名)——用长 max-age(年)+ 无需 SWR,或对可更新资产用短 max-age + SWR 平衡。

工程取舍:HTML 用"短缓存 + SWR"(快速 + 新鲜度折中)、immutable 资产用"长缓存 + 不可变"(极致命中)、动态敏感资产用"不缓存或协商";注意 SWR 与 CDN 实现(边缘异步回源)、源站负载(回源频率)、版本一致性(HTML 引用的 hash 资产必须存在,用"内容版本 → 资产映射"校验);整体目标:命中率(性能)与新鲜度(正确性)按资产类型分别最大化。

考察 SWR 的分资产策略:HTML 重新鲜度(短窗口+SWR)、Asset 重命中(长缓存 immutable),回答应体现"按资产性质差异化配置"。

#
★★★

4. Early Hints(103)状态码与 头部在服务端提速的应用

Early Hints(103)与 头部如何配合在服务端提速?

  • 103 与 preload 头的分工(提前发现 vs 提前下载)
  • 服务端实现(CDN/中间件/框架)
  • 提速效果与监控
指示浏览器"提前下载某资源",当它出现在 103 Early Hints 响应头时:浏览器在 HTML 到达前就发起关键资源请求(preload 从"HTML 解析后"提前到"响应头阶段"),而 103 本身只是"提前送达的提示"——两者组合实现"资源发现与下载再提前一个 RTT"。相比 HTML 内 preload,103 版本对高 TTFB(服务端渲染慢、回源慢)页面收益最大:等待 HTML 的同时关键 CSS/JS 已在路上。

服务端应用:CDN 规则(命中特定路径回 103 + Link 头)、应用框架(SSR 框架的 early hints 能力,按路由/权限动态决定 preload 哪些资源)、Edge 中间件(边缘逻辑直接发 103);实现要点:Link 头格式(多资源逗号分隔、as/crossorigin 完整)、只提前"最终响应确定会用的资源"(避免预取浪费带宽)、监测 LCP/TTFB 与预取命中(资源是否提前到达:resource-timing 的 startTime 早于 HTML 解析)。边界:103 无浏览器兼容风险(不支持即忽略),但 CDN/服务端支持是前提。

考察 103 + preload 的组合机制:响应头阶段预取、服务端实现路径与收益验证,回答应强调"提前一个 RTT"的时序收益。

#
★★★

5. 与 在 ESM 预加载的取舍

与 在 ESM 预加载中有哪些取舍?
  • modulepreload 的模块语义(下载+解析+缓存)
  • prefetch 的低优先级预取
  • 构建工具(Vite)的 modulepreload 注入

modulepreload 专为 ESM 设计:浏览器下载、解析并缓存模块(及依赖图),供后续 import 直接命中——比普通 preload 多做"模块解析",避免运行时逐模块发现造成的瀑布(import 链上每个模块串行请求);Vite 等构建工具自动为入口 chunk 的依赖注入 modulepreload。prefetch 是低优先级预取:空闲时下载"将来可能用"的资源(下个路由的 chunk、hover 目标页),优先级低于关键资源,不阻塞当前页。

取舍:modulepreload 用于"当前页即将执行的模块"(关键路径,高优先级、高确定性收益);prefetch 用于"未来可能访问"(低优先级、猜测性,可能浪费带宽);组合策略——首屏依赖的模块用 modulepreload(构建工具默认)、路由级懒加载 chunk 用 prefetch/preload 按策略(交互前预取 vs 到达预取);注意 prefetch 对 HTTPS 无 cookie 限制之外还有缓存语义差异,且过度 prefetch 消耗流量与带宽(移动端慎用)。工程判断:确定性需求用 preload/modulepreload,概率性需求用 prefetch,按"确定 vs 猜测"分级。

考察 ESM 预加载的工具差异:modulepreload 确定性预执行、prefetch 猜测性预取,回答应体现"确定 vs 猜测"的分级策略。

#
★★★

6. 图片优化(AVIF/WebP、响应式、懒加载、CDN)

图片优化(AVIF/WebP、响应式、懒加载、CDN)的完整策略是什么?

  • 格式选择(AVIF/WebP 的压缩与兼容)
  • 响应式与密度(srcset/sizes)
  • 懒加载与 CDN 的配合

图片优化四层:格式——WebP 广泛兼容、AVIF 压缩率更高(比 JPEG 省 50%+,适合照片与复杂图像,Chromium/Firefox 支持、Safari 16+ 支持)用 + source 按支持度降级;响应式——srcset(不同宽度候选)+ sizes(视口占位)按设备选图,宽度/密度双维度,配合 fetchpriority 标记 LCP 图高优先;懒加载——loading="lazy" 非首屏图按视口加载(但 LCP 图禁用懒加载)、占位(aspect-ratio 预留防 CLS、模糊占位/骨架);CDN——源图存储 + CDN 按需转换(尺寸/格式/质量参数化 URL:?w=400&format=avif)、压缩(质量自适应)、缓存(长缓存 + 变体键)。

工程要点:LCP 图优先(preload + 高优先级 + 格式最优化)、首屏其余图标准优化、滚动区懒加载;监控(图片字节占比、LCP 元素归属);权衡——AVIF 编码成本(CDN 转换)、过度压缩的画质损失(人眼质量分层)、sizes 写错导致选图错误(用 DevTools 验证实际选择)。整体目标:传输最小字节、渲染最大感知质量、加载不阻塞 LCP、滚动不跳动。

考察图片优化的完整链路:格式/响应式/懒加载/CDN 四层协同,回答应体现 LCP 优先与 CLS 兼顾的工程权衡。

#
★★★

7. 资源优先级(fetchpriority、 )的应用

资源优先级(fetchpriority、preload)如何应用?有何边界?

  • fetchpriority 的优先级提示语义
  • preload 与浏览器默认调度的关系
  • 误用风险与验证

fetchpriority(Priority Hints)用 fetchpriority="high/low"(img/script/link/iframe)提示浏览器资源的相对优先级:LCP 图片标 high 使其先于其他图片下载、非关键脚本标 low 让位于关键资源;preload 则"提前发现 + 提高优先级"——把 HTML 解析后期才发现的资源(CSS 引用的字体、动态依赖的模块)提前加载。两者关系:preload 影响"发现时机与初始优先级",fetchpriority 微调"同优先级队列内的次序",组合使用(LCP 图:preload + fetchpriority=high)实现精准调度。

边界与风险:优先级是"提示"而非强制——浏览器按自己的调度算法权衡(缓存、连接数、带宽);滥用 high 会劣化其他资源、滥用 preload 会抢占带宽(预取了最终不用的资源);fetchpriority 不支持时无效果(安全降级)。工程实践:只对"已验证的关键资源"(LCP 元素、首屏阻断资源)加提示,用 DevTools 网络面板验证实际优先级与时机,A/B 验证 LCP 收益后固化;避免全局铺开(提示越多,调度价值越低)。

考察优先级提示的精准应用:preload 提前发现、fetchpriority 微调次序,回答应强调"仅关键资源 + 验证收益"的克制原则。

#
★★★

8. 关键渲染路径的阻塞 CSS/JS 识别与优化

如何识别并优化关键渲染路径中的阻塞 CSS/JS?

  • render-blocking 资源的判定(CSS/同步 JS)
  • 优化手段(内联、异步、拆关键路径)
  • 验证与权衡

阻塞识别:CSS(link 默认 render-blocking,构建 CSSOM 前阻塞首绘)与同步脚本(解析 HTML 时执行,阻塞 DOM 构建)是主要阻塞源;DevTools 的 Coverage(未用代码)、性能面板的渲染时序与 Lighthouse 审计(render-blocking resources)可定位具体资源。优化手段:CSS——内联关键 CSS(首屏所需样式 inline,非关键样式异步/按需加载 media 拆分、rel="preload" as="style" onload 后切换)、压缩与合并(HTTP/2 下适度);JS——defer/async 语义化(defer 保序不阻塞解析、async 独立)、按路由拆分(懒加载非首屏逻辑)、移除阻塞的第三方脚本(async 化或延迟)。

关键路径分析(Critical Path):识别"首屏渲染必须的资源"(关键 CSS 子集 + 同步依赖),只对关键路径做最小化与内联,其余后置;权衡——内联增加 HTML 体积(TTFB 与缓存权衡:内联关键 CSS 牺牲缓存复用)、过度拆分增加请求;验证:FCP/LCP 前后对比、Lighthouse 评分、Coverage 使用率(目标 >90%)。原则:阻塞资源"必须的保留、非必须的后移",用数据验证每步优化。

考察关键渲染路径优化的方法:识别阻塞源、关键路径最小化、验证权衡,回答应体现"按阻塞贡献优化"的工程思路。

#
★★★

9. MobX 与 SSR/RSC 边界的协作

MobX 与 SSR/RSC(React Server Components)边界如何协作?

  • MobX 在 SSR 中的状态隔离(per-request store)
  • 水合(hydration)与客户端状态恢复
  • RSC 边界的响应式状态策略

MobX 在 SSR 中的核心问题:模块级 store 会被所有请求共享(跨请求状态污染)——SSR 必须"每请求创建 store 实例"(请求上下文容器:工厂创建 + 请求级注入),渲染后序列化状态到 HTML(window.INITIAL_STATE),客户端水合时用同一状态重建 store(observable 状态恢复、autorun 副作用跳过服务端)。隔离要点:避免模块单例、请求内同步渲染(避免异步泄漏)、清理响应式副作用(disposeOnUnmount)。

RSC 边界:React Server Components 在服务端执行、无状态钩子(不能使用 observer/useLocalObservable 客户端 API),因此响应式状态(MobX)位于客户端组件边界——RSC 负责服务端数据获取与静态渲染,数据经 props/serialization 传入客户端组件树,MobX store 在客户端组件层构建并驱动交互;协作模式:RSC 输出数据契约(序列化友好),客户端 MobX 层消费并维护响应式状态,两者边界清晰(服务端无状态渲染、客户端响应式交互);注意序列化限制(函数/不可序列化数据不能跨 RSC 边界)。

考察状态库与 SSR/RSC 的协作边界:per-request 隔离与水合恢复、RSC 边界的序列化约束,回答应体现"边界清晰 + 状态生命周期管理"。

#
★★★

10. SWR 的 mutate 与乐观更新 在大型表单与复杂状态的协作

SWR 的 mutate 与乐观更新如何与大型表单及复杂状态协作?

  • mutate 的本地更新机制(bindMutate、key 级)
  • 乐观更新的回滚与冲突处理
  • 与表单状态(受控/非受控)的集成

SWR 的 mutate 允许"不重新请求"直接更新缓存:mutate(key, data) 本地更新并触发重渲染,可配 revalidate 选项控制是否后台刷新;bindMutate 把更新函数绑定到具体 hook(useSWR 的 mutate 返回)。乐观更新模式:UI 先行(提交本地更新 + 乐观值)→ 请求成功用服务端数据校准(revalidate/服务器响应覆盖)→ 失败回滚到之前的快照(rollback:保存 prev 数据,catch 中 mutate 恢复),实现"即时反馈 + 最终一致"。

与大型表单协作:表单提交用乐观更新降低感知延迟,但大型表单(多字段、校验、草稿)需与本地状态协作——SWR 负责"服务端数据源",表单本地状态(受控组件/状态库)负责编辑态,提交时乐观更新 + 失败回滚;复杂状态场景(列表 + 详情 + 筛选联动)用 key 粒度更新局部而非全量重新拉取,配合 dedupe 与条件请求减少冗余请求;要点:乐观值必须"可预测回滚"(快照 + 版本号)、并发提交(多个乐观更新叠加)需合并策略、与竞态(新请求覆盖旧响应)用 abort/版本校验。

考察 SWR 缓存更新的工程模式:乐观更新 + 回滚 + 局部 key 更新,回答应体现"即时反馈与最终一致"的平衡。

#
★★

11. HTTP/2 Server Push 的废弃与替代方案(103 + preload)

HTTP/2 Server Push 为何被废弃?替代方案(103 + preload)如何工作?

  • Server Push 的机制与缺陷(浪费、缓存误判)
  • 103 + preload 的按需提前发现
  • 演进动因与工程迁移

HTTP/2 Server Push 允许服务端主动推送资源,但存在本质缺陷:推送"猜测性"资源常导致带宽浪费(客户端缓存已有、最终未使用)、无法感知客户端缓存状态(不知道 push 是否必要)、与浏览器优先级调度冲突(推送可能挤占关键资源)、HTTP/2 多路复用下收益有限,浏览器厂商逐步限制/移除(Chrome 停止对 Push 的主动使用)。替代方案是 103 Early Hints + Link: preload:服务端在响应头"提示"浏览器按需预加载(客户端决定是否请求:命中缓存即跳过、未命中才下载),把"强制推送"改为"按需提示",避免浪费同时保留提前发现收益。

工程迁移:移除 push 配置(CDN/框架层面)、改用 103 + preload 声明关键资源、对动态资源按请求上下文(路由/权限)决定提示集合;收益对比:103 方案在"提前 RTT + 零浪费 + 客户端自主"上全面优于 Push;实现检查:CDN 与框架的 early hints 支持、Link 头的资源完整性(as/crossorigin)、监测资源提前到达率(resource-timing startTime)。本质演进:从"服务端单向强推"到"客户端协商预取"。

考察 Server Push 的失败原因与替代机制:猜测性推送的浪费 vs 103 按需提示,回答应体现"客户端自主性"这一演进核心。

#
★★

12. defer/async 脚本属性的解析-执行时序差异

defer 与 async 脚本在解析-执行时序上有何差异?

  • 普通脚本/async/defer 的下载与执行时机
  • DOMContentLoaded 与执行顺序的交互
  • 工程选型(依赖顺序、首屏权衡)

三种模式:普通同步脚本——下载阻塞 HTML 解析、执行后继续解析(保序、阻塞);async——下载不阻塞解析,下载完成立即执行(执行时机不定、不保序、可能打断解析);defer——下载不阻塞解析,HTML 解析完成后、DOMContentLoaded 前按文档顺序执行(保序、不打断解析)。时序要点:async 脚本执行可能在 DOM 未完全构建时(依赖 DOM 需自行等待),defer 保证 DOM 就绪与文档顺序,适合有依赖关系的脚本。

工程选型:第三方独立脚本(分析、广告)用 async(不阻塞、顺序无关);依赖 DOM 与顺序的脚本(业务初始化、组件库)用 defer;首屏关键逻辑内联或 defer;注意 async 脚本间无法保证顺序(相互依赖需合并或用 defer);LCP 优化中两者都"不阻塞解析",但 async 执行可能抢主线程(长任务影响 INP),需监控执行时机;历史边界:老浏览器对 defer 的 bug(已过时),现代工程以 defer 为主、async 用于独立脚本。

考察脚本加载语义的精确差异:async 完成即执行(无序)、defer 解析后保序执行,回答应落到依赖与首屏权衡。

#
★★

13. Service Worker 缓存策略(stale-while-revalidate、cache-first、network-first)

Service Worker 的缓存策略(stale-while-revalidate、cache-first、network-first)如何选择?

  • 三类策略的请求路径与新鲜度
  • 按资源类型匹配策略
  • 版本更新与缓存清理

Service Worker 缓存策略:cache-first——先查缓存命中即返回(不触网),未命中回源并缓存;最快但新鲜度差,适合不可变资源(hash 文件名资产)。network-first——先请求网络,失败(离线)回退缓存;新鲜但慢且离线兜底,适合对新鲜度敏感的资源(HTML、API 部分场景)。stale-while-revalidate——先返回缓存(stale)同时后台请求更新缓存,下次命中新值;快 + 新鲜度折中,适合可容忍短暂延迟更新的内容(列表、配置)。

工程选择:按资源类型映射——hash 资产 cache-first(长缓存)、HTML 页面 network-first 或 SWR(新鲜 + 离线)、API 按业务(读多写少的 SWR、实时性要求高的 network-first)、图片/字体 cache-first + 版本管理;配套:SWR 的"版本更新与缓存清理"(cache version 号升级时清旧缓存、navigation preload 加速回源、更新流程(skipWaiting/clientsClaim));监控缓存命中率与离线可用性。权衡核心:新鲜度要求 vs 性能收益,按资源语义分桶配置。

考察 SW 缓存策略的语义差异:命中路径与新鲜度光谱,回答应体现"按资源类型分桶"的配置方法。

#
★★

14. Resource Hints(modulepreload / imagesrcset)

Resource Hints(modulepreload / imagesrcset)有哪些应用?

  • modulepreload 的模块预加载语义
  • imagesrcset 的响应式图片提示
  • 与浏览器调度的配合

modulepreload(link rel="modulepreload")专用于 ESM 模块:下载、解析并缓存模块与其依赖,后续 import 命中缓存,消除运行时模块发现的串行瀑布(import 链深度 N 时逐个请求);构建工具(Vite/Rollup 输出)自动注入入口依赖链的 modulepreload。imagesrcset(link rel="preload" as="image" imagesrcset=...)允许对"响应式图片"做预加载提示:预先告诉浏览器候选图集合(多个宽度),浏览器按视口选择并提前下载——解决"LCP 是 srcset 图但无法预加载"的问题(普通 preload 只有单 URL)。

应用场景:SPA 路由级模块(当前页即将执行的 chunk)用 modulepreload;LCP 响应式图用 imagesrcset preload;配合 fetchpriority 调整优先次序;浏览器调度(同优先级内按需、带宽与缓存感知)决定了提示是"建议"而非强制。工程要点:modulepreload 注入范围控制(只关键链,避免海量提示)、imagesrcset 的 sizes 与图片实际使用一致(预取错尺寸浪费)、监控预取命中与 LCP 收益、不支持时安全降级(只是回到串行发现)。

考察两类现代 Resource Hints:modulepreload 消除模块瀑布、imagesrcset 预取响应式 LCP 图,回答应包含注入范围与验证。

#
★★

15. Preload/Prefetch/Preconnect/Prerender 资源提示的优先级与浏览器协作工程价值

Preload/Prefetch/Preconnect/Prerender 资源提示的优先级与浏览器协作有何工程价值?

  • 四种提示的语义与优先级
  • 浏览器调度与带宽分配
  • 组合使用的场景决策

四种 Resource Hints:preload——当前页关键资源提前加载(高优先级、确定性);prefetch——未来可能用的资源(低优先级、空闲时下载);preconnect——提前建立跨域连接(DNS/TCP/TLS,用于即将请求的第三方域);prerender——预渲染整个页面(最高成本:下载+执行+渲染,用于高概率即将访问的页面,现行实现主要是 Speculation Rules 的 prerender 或旧 link prerender 降级)。优先级:preload 高于 prefetch,preconnect 不占带宽只占连接,prerender 成本最高。

浏览器协作:提示是"建议"——浏览器按优先级、连接数、缓存与用户环境(数据节省模式)调度;工程价值:preload 保障 LCP 资源、prefetch 降低导航延迟(路由 hover/可见时预取)、preconnect 削减第三方(字体、CDN、分析)连接开销、prerender 实现"零延迟导航"(但需谨慎:成本高、可能浪费)。决策矩阵:确定性需求(当前页必须)→ preload;概率需求(下一步可能)→ prefetch/preconnect;高置信即将访问 → prerender;成本排序与收益匹配,避免"处处提示"稀释价值。

考察资源提示体系的完整语义与成本梯度:preload/prefetch/preconnect/prerender 按确定性与成本决策。

#
★★

16. Service Worker 与 HTTP 缓存层级的工程取舍

Service Worker 缓存与 HTTP 缓存层级的工程取舍是什么?

  • 缓存层级(内存/HTTP/SW/存储)的交互
  • SW 控制请求的时机与能力
  • 分层缓存策略的协同

浏览器缓存层级:内存缓存 → HTTP 缓存(Cache-Control/ETag 协商)→ Service Worker 缓存(Cache Storage API)→ 网络;SW 处于"应用层代理"位置:fetch 事件先于 HTTP 缓存处理请求(SW 决定是否触网),因此 SW 是"最灵活的控制层"(可编程缓存策略、离线能力、请求改写),HTTP 缓存是"基础效率层"(标准语义、CDN 参与)。取舍:SW 强(离线、策略、版本管理)但增加复杂度(生命周期、更新、调试),HTTP 缓存简单高效但僵化(不可编程、离线依赖浏览器默认)。

工程协同:SW 对"运行时"(页面、API)做策略控制(network-first/SWR),HTTP 缓存管"构建期"(hash 资产长缓存);层级注意——SW 缓存响应也要尊重服务端缓存头(防止双重缓存混乱:SW 把带短 max-age 的响应缓存后,回源频率由 SW 策略决定);更新治理:SW 版本与资产版本联动(新 SW 清旧缓存)、避免"SW 缓存了过期 HTML 又走 HTTP 协商"的歧义。原则:HTTP 层管标准效率、SW 层管应用策略,各司其职、显式协同。

考察缓存层级的协作模型:HTTP 基础层 + SW 策略层的分工,回答应体现"标准语义 + 可编程策略"的协同。

#
★★

17. 字体子集化(subset)与 unicode-range 的工程化

字体子集化(subset)与 unicode-range 如何工程化?

  • unicode-range 的分片加载机制
  • 子集化工具与中文字体策略
  • 字体加载对 LCP/CLS 的影响

unicode-range 让浏览器按"字符范围"按需下载字体分片:@font-face 声明多个子集(latin、中文常用字、生僻字),页面只用到的字符命中对应子集才下载——避免下载整包字体(中文全字库动辄数 MB)。子集化工具(fonttools、glyphhanger、子集化服务)按页面字符集(text 扫描)或 Unicode 范围生成分片,常见策略:中文按"常用字子集 + 生僻字兜底"分片(常用 3500 字/GB2312 分片),动态内容(用户输入)需兜底子集。

工程化:子集化 + 字体压缩(WOFF2)+ 加载策略(font-display: swap/optional 减少 FOIT/FOUT;关键字体 preload;font-size-adjust/size-adjust 防切换偏移)组合;对 CLS:字体切换(fallback 与 webfont 尺寸差异)产生布局偏移,用 size-adjust 对齐度量;对 LCP:文本 LCP 依赖字体加载完成——子集化缩小首屏字体字节、optional 允许用 fallback 先绘。监控:字体加载字节、切换对 CLS/LCP 的贡献、分片命中率(是否下载了用不到的子集)。

考察字体性能的系统方案:unicode-range 分片、子集化工具、加载与切换策略,回答应体现对 LCP/CLS 的双重治理。

#
★★

18. HTTP 缓存(强缓存、协商缓存)的配置

HTTP 强缓存与协商缓存如何配置?有何工程实践?

  • 强缓存(Cache-Control: max-age)与协商缓存(ETag/Last-Modified)
  • 各资产类型的缓存头策略
  • 缓存失效与版本管理

强缓存:Cache-Control: max-age=31536000 等,命中时浏览器/CDN 直接使用本地副本(零请求),适合不可变内容;协商缓存:ETag(内容指纹)/Last-Modified(时间),强缓存过期后发条件请求(If-None-Match),服务端返回 304(无 body)或 200——保证新鲜度同时节省传输。配置策略:hash 文件名资产(JS/CSS/图片)用"max-age 一年 + immutable"(内容变文件名必变);HTML 用"no-cache 或短 max-age + ETag"(每次协商、按需更新);API 用 no-store 或按业务缓存。

工程实践:构建工具(文件名 hash、manifest 映射)、CDN 的缓存键(URL + Vary)与规则、缓存头与 CI 发布流程配合(新版本 HTML 引用新 hash 资产,旧资产自然失效);风险:错误长缓存导致旧版本存活(需 URL 版本化而非仅覆盖同名文件)、协商缓存失效慢(stale 窗口);监控:缓存命中率(CDN 日志、resource-timing transferSize=0 判定内存命中)、失效策略演练。原则:"不可变内容永久缓存、可变内容协商校验"。

考察 HTTP 缓存的完整配置体系:强/协商语义、按资产类型分桶、版本化失效,回答应体现"不可变长缓存、可变协商"的原则。

#
★★

19. Zag.js 在跨标签/跨窗口的工程价值

Zag.js 在跨标签/跨窗口场景有哪些工程价值?

  • Zag.js 的 headless 状态机架构
  • 跨窗口状态同步(BroadcastChannel/store)
  • 工程应用(协作、共享会话)

Zag.js 是无头 UI 状态机库:用有限状态机(XState 驱动)建模组件状态(dialog/tabs/toast 等),状态与渲染分离(框架无关:React/Vue/原生皆可接入)。跨标签/跨窗口价值:状态机暴露"可序列化状态 + 事件接口",使状态可被外部持久化/传输——配合 BroadcastChannel/localStorage 同步事件,可实现在多个标签页间同步组件状态(一处打开弹窗,另一标签同步、登录态同步、表单草稿联动);状态机保证同步过程的确定性(事件驱动、状态合法迁移),避免手动状态同步的竞态。

工程应用:多窗口协作(富文本共享会话)、单点登录态跨标签即时刷新、全局通知去重(多个标签只弹一次 toast);工程要点:序列化状态的安全边界(不跨窗口传输敏感数据)、事件风暴控制(广播节流/只广播状态变更)、与 Storage 事件(同源跨标签)和 BroadcastChannel(同源、容量大)的选择;价值总结:状态机把"跨窗口一致性"从命令式对账变为"声明式状态同步"。

考察 headless 状态机在跨窗口场景的应用:可序列化状态 + 事件广播实现确定性同步,回答应体现状态机模式的迁移优势。

#

20. URL state 与 useSearchParams 在测试与可维护性的工程价值

URL state 与 useSearchParams 在测试与可维护性上有哪些工程价值?

  • URL 作为可序列化状态源的语义
  • useSearchParams 的类型化与可恢复性
  • 测试友好(注入 URL 断言状态)

URL state(把筛选、分页、查询等 UI 状态放入 query params)的价值:状态可分享、可收藏、可刷新恢复、可回溯(前进后退)——"URL 即状态源",后端/监控可直接读取当前视图上下文;useSearchParams(React Router)提供声明式读写(get/set、类型化 parse),配合序列化器(如 qs、schema 校验)保证结构稳定。可维护性:状态显式化(不再藏在组件内存里)、跨组件共享免状态库、路由级状态集中管理。

测试价值:测试通过"构造 URL 进入页面"直接驱动状态(无需 UI 操作序列)、断言 URL 变化验证状态流转、刷新/恢复场景可测(URL → 状态 → UI 闭环);配合 TanStack Router 的 schema 校验,非法 URL 参数在边界被拦截(容错降级),测试覆盖"URL 异常 → 默认值"路径。取舍:URL 状态粒度(太长 URL 不适合大数据)、敏感数据不入 URL(隐私);工程上"可分享状态入 URL、瞬态状态留内存"为分界。

考察 URL 状态模式的价值:可恢复可分享的单一事实源、测试注入便利,回答应体现"URL 即状态契约"的边界判断。

#

21. 资源加载与缓存涉及哪些浏览器内部关键路径与实现原理,应如何结合业务场景做性能瓶颈定位

资源加载与缓存涉及哪些浏览器内部关键路径与实现原理?如何结合业务场景做瓶颈定位?

  • 加载链路:URL 解析、连接、缓存查找、解析执行
  • 缓存查找顺序与命中断言(transferSize)
  • 场景化定位流程(DevTools、timing、采样)

资源加载的浏览器内部路径:输入 URL → DNS 解析 → 连接(TCP/TLS/QUIC)→ 缓存查找(内存 → HTTP 缓存 → SW → 网络)→ 请求与响应(CDN 边缘)→ 解析(HTML/CSS/JS 各自解析器)→ 执行与渲染(主线程)。关键原理:缓存查找顺序(内存最快、HTTP 按 Cache-Control/ETag、SW 可编程拦截)、preload/prefetch 的发现时机(解析器提示 vs 运行时)、HTTP/2 多路复用(同连接并发)、第三方脚本的执行阻塞。瓶颈定位方法:DevTools Network(时序瀑布:TTFB/Content Download 分段、优先级、是否缓存(transferSize=0/from cache)、阻塞时间)、Performance 面板(主线程任务与渲染)、timing API(navigation/resource 细分)。

场景化流程:业务场景(首屏慢/交互卡/离线失败)→ 假设 → 数据验证:首屏慢先拆 TTFB(网络/服务端)与资源(哪个资源慢、为何慢:缓存 miss、未预加载、包体大);交互卡看主线程(长任务/渲染);离线问题看 SW 策略与缓存覆盖;用 Lighthouse 审计 + RUM 字段交叉确认(Lab 定位根因、Field 确认影响范围)。关键思维:把"现象"分解为"链路环节 + 资源对象 + 时间分段",用工具定位到具体环节再优化。

考察加载与缓存的内部机制 + 定位方法论:链路理解、缓存断言、场景化分解,回答应体现"机制 → 假设 → 数据验证"的流程。