核心概念
Suspense 是 React 中用于声明式处理异步操作和渐进式加载的并发特性。它允许组件在等待某些条件(如数据加载、代码分割)时”挂起”渲染,并显示一个降级的 UI,待条件满足后再继续渲染完整内容。
工作原理
基本机制
import { Suspense, lazy } from 'react';
// 动态导入 - 代码分割
const HeavyComponent = lazy(() => import('./HeavyComponent'));
const DataComponent = lazy(() => import('./DataComponent'));
function App() {
return (
<div>
{/* 立即渲染的静态内容 */}
<header>应用头部</header>
{/* 渐进式加载的异步内容 */}
<Suspense fallback={<div>加载中...</div>}>
<HeavyComponent />
</Suspense>
<Suspense fallback={<div>加载用户数据...</div>}>
<DataComponent />
</Suspense>
</div>
);
}挂起与恢复流程
- 渲染开始:React 开始渲染组件树
- 遇到异步依赖:组件尝试读取尚未准备好的数据或代码
- 抛出 Promise:组件抛出 Promise 信号表示需要等待
- 挂起渲染:React 暂停当前组件的渲染
- 显示 Fallback:向上查找最近的 Suspense 边界,显示
fallbackUI - Promise 解决:异步操作完成
- 重新渲染:React 重新尝试渲染被挂起的组件
- 显示完整内容:渲染成功,替换 fallback UI
渐进式加载模式
1. 代码分割与懒加载
// 路由级别的渐进加载
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const Settings = lazy(() => import('./pages/Settings'));
function Router() {
const [currentRoute, setCurrentRoute] = useState('home');
return (
<Suspense fallback={<GlobalLoading />}>
{currentRoute === 'home' && <Home />}
{currentRoute === 'about' && <About />}
{currentRoute === 'settings' && <Settings />}
</Suspense>
);
}
// 组件级别的渐进加载
function ProductPage({ productId }) {
return (
<div>
{/* 核心信息立即显示 */}
<ProductHeader productId={productId} />
{/* 次要内容渐进加载 */}
<Suspense fallback={<ReviewsSkeleton />}>
<ProductReviews productId={productId} />
</Suspense>
<Suspense fallback={<RecommendationsSkeleton />}>
<RelatedProducts productId={productId} />
</Suspense>
</div>
);
}2. 数据获取的渐进式处理
// 简单的数据获取包装器
function fetchData(url) {
let status = 'pending';
let result;
let suspender = fetch(url)
.then(response => response.json())
.then(data => {
status = 'success';
result = data;
})
.catch(error => {
status = 'error';
result = error;
});
return {
read() {
if (status === 'pending') {
throw suspender; // 抛出 Promise,触发 Suspense
} else if (status === 'error') {
throw result; // 抛出错误,触发 Error Boundary
} else if (status === 'success') {
return result;
}
}
};
}
// 在组件中使用
const userData = fetchData('/api/user/123');
function UserProfile() {
const user = userData.read(); // 可能挂起
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
// 在 Suspense 边界内使用
function App() {
return (
<Suspense fallback={<UserProfileSkeleton />}>
<UserProfile />
</Suspense>
);
}3. 嵌套 Suspense 与逐步揭示
function Dashboard() {
return (
<div className="dashboard">
{/* 第一层:关键指标快速显示 */}
<Suspense fallback={<KeyMetricsSkeleton />}>
<KeyMetrics />
{/* 第二层:详细数据稍后显示 */}
<Suspense fallback={<ChartsSkeleton />}>
<AnalyticsCharts />
{/* 第三层:辅助信息最后显示 */}
<Suspense fallback={<RecommendationsSkeleton />}>
<Recommendations />
</Suspense>
</Suspense>
</Suspense>
</div>
);
}用户体验优化模式
1. 骨架屏设计
// 专业的骨架屏组件
function ProductCardSkeleton() {
return (
<div className="product-card-skeleton">
<div className="image-placeholder"></div>
<div className="content">
<div className="title-line"></div>
<div className="price-line"></div>
<div className="button-placeholder"></div>
</div>
</div>
);
}
function ReviewsSkeleton() {
return (
<div className="reviews-skeleton">
<div className="review-header">
<div className="avatar"></div>
<div className="user-info">
<div className="name-line"></div>
<div className="date-line"></div>
</div>
</div>
<div className="review-content">
<div className="text-line"></div>
<div className="text-line short"></div>
</div>
</div>
);
}2. 智能加载策略
import { Suspense, useState, useEffect } from 'react';
function SmartSuspense({ children, fallback, delay = 200 }) {
const [showFallback, setShowFallback] = useState(false);
useEffect(() => {
// 延迟显示 fallback,避免快速加载时的闪烁
const timer = setTimeout(() => {
setShowFallback(true);
}, delay);
return () => clearTimeout(timer);
}, [delay]);
return (
<Suspense fallback={showFallback ? fallback : null}>
{children}
</Suspense>
);
}
// 使用智能 Suspense
function ProductPage() {
return (
<div>
<SmartSuspense
fallback={<ProductGallerySkeleton />}
delay={100} // 100ms 内加载完成就不显示骨架屏
>
<ProductGallery />
</SmartSuspense>
<SmartSuspense
fallback={<ProductDetailsSkeleton />}
delay={300} // 次要内容可以容忍更长的延迟
>
<ProductDetails />
</SmartSuspense>
</div>
);
}错误处理与边界管理
import { Suspense } from 'react';
import ErrorBoundary from './ErrorBoundary';
function RobustAsyncComponent() {
return (
<ErrorBoundary
fallback={<ErrorComponent />}
onRetry={() => window.location.reload()}
>
<Suspense fallback={<LoadingComponent />}>
<AsyncContent />
</Suspense>
</ErrorBoundary>
);
}
// 多个 Suspense 边界的独立错误处理
function ComplexPage() {
return (
<div>
<ErrorBoundary fallback={<HeaderError />}>
<Suspense fallback={<HeaderSkeleton />}>
<PageHeader />
</Suspense>
</ErrorBoundary>
<ErrorBoundary fallback={<ContentError />}>
<Suspense fallback={<ContentSkeleton />}>
<PageContent />
</Suspense>
</ErrorBoundary>
<ErrorBoundary fallback={<SidebarError />}>
<Suspense fallback={<SidebarSkeleton />}>
<PageSidebar />
</Suspense>
</ErrorBoundary>
</div>
);
}性能优化实践
1. 预加载策略
// 预加载关键组件
const HeavyComponent = lazy(() => import('./HeavyComponent'));
function App() {
const [showHeavy, setShowHeavy] = useState(false);
// 预加载组件
useEffect(() => {
import('./HeavyComponent');
}, []);
// 或者基于用户交互预测
const handleHover = useCallback(() => {
import('./HeavyComponent');
}, []);
return (
<div>
<button
onMouseEnter={handleHover}
onClick={() => setShowHeavy(true)}
>
加载重型组件
</button>
{showHeavy && (
<Suspense fallback={<div>快速加载中...</div>}>
<HeavyComponent />
</Suspense>
)}
</div>
);
}2. 流式 SSR 集成
// Next.js 中的流式 Suspense
async function ProductPage({ params }) {
return (
<div>
<ProductHeader productId={params.id} />
<Suspense fallback={<ReviewsSkeleton />}>
<Reviews productId={params.id} />
</Suspense>
<Suspense fallback={<RecommendationsSkeleton />}>
<Recommendations productId={params.id} />
</Suspense>
</div>
);
}设计原则总结
1. 渐进式体验层次
- 立即显示:静态内容和关键信息
- 快速加载:用户当前视图内的内容
- 延迟加载:非关键内容和预测性内容
- 按需加载:用户交互触发的功能
2. 优雅降级策略
- 骨架屏 → 提供结构和加载预期
- 错误边界 → 防止级联失败
- 重试机制 → 自动恢复能力
- 离线降级 → 基础功能保障
3. 性能与体验平衡
- 避免闪烁:智能延迟显示 fallback
- 感知性能:骨架屏比加载动画更好
- 优先级调度:关键内容优先加载
- 预测加载:基于用户行为预加载
Suspense 将渐进式加载从技术实现提升到了声明式设计的层面,让开发者能够更自然地表达加载状态和依赖关系,为用户创造平滑、可预测的渐进式体验。