尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Cherry Studio 前端性能实践:为 Script 标签正确使用 defer 与 async,消除渲染阻塞

Cherry Studio 前端性能实践:为 Script 标签正确使用 defer 与 async,消除渲染阻塞 Cherry Studio 前端性能实践为 Script 标签正确使用 defer 与 async消除渲染阻塞【免费下载链接】cherry-studioAI productivity studio with smart chat, autonomous agents, and 300 assistants. Unified access to frontier LLMs项目地址: https://gitcode.com/GitHub_Trending/ch/cherry-studio导读本文基于仓库内 rendering-script-defer-async.md 这一条 Vercel React 最佳实践规则系统讲解script标签defer与async属性的工作原理、选择原则与常见误用并结合 Cherry Studio 仓库中 Electron 渲染进程的 Vite 构建产物说明该规则在真实项目中的落地形态。读完本文你将能够准确判断任意脚本该用defer、async还是保持默认理解脚本加载策略对 First Contentful PaintFCP与 Time to InteractiveTTI的影响并掌握 Next.js 中next/script的等价写法。问题本质不带 defer/async 的脚本为什么会阻塞渲染HTML 解析器是串行工作的。当浏览器在解析 HTML 时遇到一个既没有defer也没有async的script标签它必须暂停 HTML 解析暂停生成 DOM 树下载脚本文件若尚未在缓存中同步执行脚本恢复 HTML 解析。这一机制在仓库规则中被定性为Impact: HIGH消除渲染阻塞脚本下载与执行期间页面既无法产出可见内容也无法响应交互直接拉长 FCP 与 TTI 两个核心 Web 性能指标。规则原文的描述是Script tags withoutdeferorasyncblock HTML parsing while the script downloads and executes. This delays First Contentful Paint and Time to Interactive.该规则隶属于.agents/skills/vercel-react-best-practices技能包中「Rendering Performance渲染性能MEDIUM 优先级」类别是 Vercel 工程团队沉淀的 62 条规则之一在编译产物 AGENTS.md 中编号为6.8。它解决的问题属于前端性能优化的经典领域适用于任何以 HTML JavaScript 驱动的项目包括 Electron 桌面应用。defer 与 async 的核心差异两者都能让脚本并行下载不阻塞 HTML 解析关键区别在执行时机与执行顺序特性deferasync下载时机与 HTML 解析并行与 HTML 解析并行执行时机HTML 解析完成后DOMContentLoaded 之前下载完成立即执行随时可能打断解析执行顺序按文档中出现顺序执行不保证顺序谁先下载完谁先执行适用场景依赖 DOM 或依赖其他脚本的脚本相互独立、无依赖的脚本如统计埋点规则原文给出了直接可用的判断准则deferDownloads in parallel, executes after HTML parsing completes, maintains execution order —— 用于依赖 DOM 结构、或依赖其他脚本执行顺序的脚本asyncDownloads in parallel, executes immediately when ready, no guaranteed order —— 用于相互独立的脚本典型如第三方分析analytics脚本。注意defer脚本虽然推迟到解析结束后执行但依然会在DOMContentLoaded事件触发之前运行因此它能安全访问完整的 DOM而不会阻塞首屏解析本身。反例未标注的脚本标签会阻塞渲染规则给出了一个典型的错误写法——在自定义Document组件中裸写script既不声明defer也不声明asyncexport default function Document() { return ( html head script srchttps://example.com/analytics.js / script src/scripts/utils.js / /head body{/* content */}/body /html ) }这段代码有两个问题两个脚本都会阻塞 HTML 解析——尤其放在head中时body里的内容必须等脚本下载并执行完才开始渲染即使第一个脚本是无关紧要的第三方分析脚本也会拖累首屏。正例按依赖关系选择 defer 或 async规则给出的修正版本用注释明确了选择依据export default function Document() { return ( html head {/* Independent script - use async */} script srchttps://example.com/analytics.js async / {/* DOM-dependent script - use defer */} script src/scripts/utils.js defer / /head body{/* content */}/body /html ) }设计要点拆解第三方分析脚本analytics.js用async它不依赖页面 DOM也不依赖任何其他脚本下载完立刻执行即可把对主文档的干扰降到最低工具脚本utils.js用defer它很可能要访问 DOM 或挂载事件defer保证它在 HTML 解析结束后按声明顺序执行两个脚本都改为并行下载HTML 解析不再被任何一次下载/执行阻塞。替代方案Next.js 中优先使用 next/script 的 strategy规则特别提示在 Next.js 项目里应优先使用next/script组件而不是裸script标签通过strategy属性声明加载策略import Script from next/script export default function Page() { return ( Script srchttps://example.com/analytics.js strategyafterInteractive / Script src/scripts/utils.js strategybeforeInteractive / / ) }两种 strategy 与原生属性的对应关系strategybeforeInteractive脚本在页面成为可交互hydration之前加载用于必须在首屏交互前就绪的关键脚本等价于在文档早期以较高优先级加载其内部处理接近defer的思路但由框架托管加载时机strategyafterInteractive页面可交互后再加载适合分析、埋点等非关键第三方脚本语义上对应“不阻塞渲染”的诉求等价于async场景。使用next/script的收益在于策略声明化、加载时机由框架统一调度并且能规避在head中手工管理 script 标签时的顺序与优先级问题。仓库印证Cherry Studio 渲染进程如何加载脚本Cherry Studio 是一个 Electron 桌面应用其渲染进程基于 Vite 构建多个窗口的入口 HTML 分别位于 src/renderer/windows 目录下。以主窗口入口 index.html 为例script console.time(init) /script script typemodule src/windows/main/entryPoint.tsx/script这段代码体现了本条规则在实际项目中的两种“天然满足”形态typemodule的 ES Module 脚本默认具备 defer 行为浏览器对模块脚本的语义是“解析完 HTML 后再按依赖图顺序执行”因此入口entryPoint.tsx不会阻塞初始 HTML 解析。这正是本规则在 Vite/Electron 类工程中的主流落地方式——现代打包器产出的入口几乎都是 module 脚本内联小脚本保持极简console.time(init)这类同步内联脚本体积极小、执行时间可忽略放在/body前不会造成可感知的渲染阻塞同时用于记录启动时间配合 docs/references/observability.md 所述的可观测性方案做启动性能打点。此外该窗口 HTML 中通过 CSP meta 声明了script-src self unsafe-eval unsafe-inline *允许加载外部脚本若未来在仓库中引入第三方统计或远程脚本就应严格套用本规则独立脚本加async依赖型脚本加defer并尽可能走构建器的模块化引入路径保持“非阻塞优先”。选择决策速查场景推荐方案脚本需访问 DOM、或依赖其他脚本的执行顺序defer独立第三方脚本分析、埋点、AB 实验async关键首屏逻辑、必须在交互前就绪内联小脚本 typemodule或next/script的beforeInteractiveNext.js 中的非关键第三方库next/script的afterInteractiveVite/打包器产出的应用入口保持typemodule模块脚本默认 defer边界与注意事项不要对typemodule的脚本再手动加defer模块脚本本身就按 defer 语义执行重复声明没有意义反而可能引起误解async与defer共存时以async为准同一脚本标签上同时出现两个属性时async优先执行时机不受顺序约束动态插入的脚本默认是 async通过document.createElement(script)动态添加到 DOM 的脚本默认即异步加载行为与静态async脚本类似第三方脚本的未知依赖要谨慎当无法确认某个第三方脚本是否依赖 DOM 或其他脚本时优先选择defer保序比async乱序更安全性能收益有前提defer/async解决的是“下载执行不阻塞解析”它不改变脚本本身的体积与执行耗时真正需要裁减体积时应配合本技能包中bundle-*类规则如 bundle-defer-third-party.md 中“用动态加载把非关键三方库推迟到 hydration 之后”的做法一起治理。小结defer与async是前端性能优化中成本最低、收益最直接的改进之一二者都将脚本下载从“串行阻塞”改为“并行进行”区别只在执行时机与顺序保障——defer保序、解析后执行async就绪即执行、不保序。将这条规则内化为编码习惯依赖 DOM 用defer、独立埋点用async、Next.js 用next/script的strategy即可系统性消除脚本带来的渲染阻塞守住 FCP 与 TTI 等核心指标。【免费下载链接】cherry-studioAI productivity studio with smart chat, autonomous agents, and 300 assistants. Unified access to frontier LLMs项目地址: https://gitcode.com/GitHub_Trending/ch/cherry-studio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表