Skip to content
C.W.K.
Stream
Lesson 06 of 09 · published

Parallel & Sequential Fetching

~20 min · Promise.all, waterfall, perf

Level 0Curious
0 XP0/68 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

Sequential await is a waterfall

Each await on its own line waits for the previous one. Three independent fetches at 200/300/250ms become a 750ms render. JavaScript doesn't magically parallelize them.

Independent fetches go in Promise.all

If A doesn't depend on B, fire them together and wait for both. Total time = max, not sum.

Sequential is fine when needed

If B's URL or query depends on A's result (getUser(id)getPostsByAuthor(user.id)), the waterfall is intentional. Don't twist your code into knots to avoid it.

Suspense lets you stream waterfalls anyway

Even when fetches must run sequentially, Suspense boundaries let the page stream — the user sees the cheap parts immediately, the slower parts arrive when ready.

Parallelize only requests that are independent and whose downstream service can accept the concurrency. Start the Promises together, then wait as a group. Keep genuine dependencies sequential and place their slow subtree behind Suspense when the rest of the page can proceed. Maximum parallelism is not maximum throughput. A small database pool or rate-limited API can turn a burst into a longer queue. Include service capacity when deciding how wide to fan out. Trace three artificial delays sequentially and with Promise.all, then repeat with a constrained connection pool. Decide whether one failed request should cancel the group or whether separate error boundaries should preserve partial content.

Code

❌ Sequential — slow·tsx
export default async function Page() {
  const user = await getUser();           // 200ms
  const posts = await getPosts();          // 300ms
  const stats = await getStats();          // 250ms
  // Total: ~750ms
  return <Dashboard user={user} posts={posts} stats={stats} />;
}
✅ Parallel — fast·tsx
export default async function Page() {
  const [user, posts, stats] = await Promise.all([
    getUser(),
    getPosts(),
    getStats(),
  ]);
  // Total: ~max(200, 300, 250) = 300ms
  return <Dashboard user={user} posts={posts} stats={stats} />;
}
Legitimate waterfall·tsx
export default async function UserPostsPage({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params;
  const user = await getUser(id);                     // need user first
  const posts = await getPostsByAuthor(user.id);       // depends on user
  return <PostList user={user} posts={posts} />;
}

External links

Exercise

Find a Server Component with three sequential awaits. Convert to Promise.all when independent, and confirm the page-load time drops correspondingly.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.