--- title: 战略性的 Suspense 边界 impact: HIGH impactDescription: 更快的首次绘制 tags: async, suspense, streaming, layout-shift --- ## 战略性的 Suspense 边界 不要在异步组件中等待数据后再返回 JSX,而应使用 Suspense 边界在数据加载期间更快地展示外层 UI。 **错误做法(外层 UI 被数据请求阻塞):** ```tsx async function Page() { const data = await fetchData() // 阻塞整个页面 return (
Sidebar
Header
Footer
) } ``` 整个布局都要等待数据,即使只有中间部分需要它。 **正确做法(外层 UI 立即显示,数据流式传入):** ```tsx function Page() { return (
Sidebar
Header
}>
Footer
) } async function DataDisplay() { const data = await fetchData() // 仅阻塞该组件 return
{data.content}
} ``` Sidebar、Header 和 Footer 立即渲染。只有 DataDisplay 等待数据。 **备选方案(在组件间共享 Promise):** ```tsx function Page() { // 立即发起请求,但不等待 const dataPromise = fetchData() return (
Sidebar
Header
}>
Footer
) } function DataDisplay({ dataPromise }: { dataPromise: Promise }) { const data = use(dataPromise) // 解包 Promise return
{data.content}
} function DataSummary({ dataPromise }: { dataPromise: Promise }) { const data = use(dataPromise) // 复用同一个 Promise return
{data.summary}
} ``` 两个组件共享同一个 Promise,因此只发起一次请求。布局立即渲染,同时两个组件一起等待。 **何时不应使用此模式:** - 影响布局决策的关键数据(影响定位) - 首屏之上对 SEO 至关重要的内容 - 小型、快速的查询,Suspense 开销不值得 - 当你想避免布局偏移时(加载 → 内容跳变) **权衡取舍:** 更快的首次绘制 vs 潜在的布局偏移。根据你的用户体验优先级进行选择。