frontend-async-best-practices

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Async Best Practices

异步代码最佳实践

Performance optimization patterns for asynchronous JavaScript code. Contains 5 rules focused on eliminating request waterfalls and maximizing parallelism.
Impact: CRITICAL - Waterfalls are the #1 performance killer. Each sequential await adds full network latency.
面向JavaScript异步代码的性能优化模式。包含5条规则,重点在于消除请求瀑布并最大化并行性。
影响程度:严重 - 请求瀑布是头号性能杀手。每个顺序执行的await都会增加完整的网络延迟。

When to Apply

适用场景

Reference these guidelines when:
  • Writing Remix loaders or actions
  • Implementing data fetching logic
  • Working with multiple async operations
  • Reviewing code for waterfall patterns
  • Optimizing response times
参考本指南的场景:
  • 编写Remix加载器或操作
  • 实现数据获取逻辑
  • 处理多个异步操作
  • 评审代码中的请求瀑布模式
  • 优化响应时间

Rules Summary

规则摘要

parallel (CRITICAL) — @rules/parallel.md

并行执行(严重)——@rules/parallel.md

Use
Promise.all()
for independent operations.
typescript
// Bad: 3 sequential round trips
const user = await fetchUser();
const posts = await fetchPosts();
const comments = await fetchComments();

// Good: 1 parallel round trip
const [user, posts, comments] = await Promise.all([
  fetchUser(),
  fetchPosts(),
  fetchComments(),
]);
对独立操作使用
Promise.all()
typescript
// 不良实践:3次顺序网络请求
const user = await fetchUser();
const posts = await fetchPosts();
const comments = await fetchComments();

// 最佳实践:1次并行网络请求
const [user, posts, comments] = await Promise.all([
  fetchUser(),
  fetchPosts(),
  fetchComments(),
]);

defer-await (HIGH) — @rules/defer-await.md

延迟await(高)——@rules/defer-await.md

Move await into branches where actually used.
typescript
// Bad: always waits even when skipping
async function handle(skip: boolean) {
  let data = await fetchData();
  if (skip) return { skipped: true };
  return process(data);
}

// Good: only waits when needed
async function handle(skip: boolean) {
  if (skip) return { skipped: true };
  let data = await fetchData();
  return process(data);
}
将await移至实际需要使用的代码分支中。
typescript
// 不良实践:即使跳过逻辑也会等待
async function handle(skip: boolean) {
  let data = await fetchData();
  if (skip) return { skipped: true };
  return process(data);
}

// 最佳实践:仅在需要时等待
async function handle(skip: boolean) {
  if (skip) return { skipped: true };
  let data = await fetchData();
  return process(data);
}

dependencies (CRITICAL) — @rules/dependencies.md

依赖处理(严重)——@rules/dependencies.md

Chain dependent operations, parallelize independent ones.
typescript
// Bad: profile waits for config unnecessarily
const [user, config] = await Promise.all([fetchUser(), fetchConfig()]);
const profile = await fetchProfile(user.id);

// Good: profile starts as soon as user resolves
const userPromise = fetchUser();
const profilePromise = userPromise.then((user) => fetchProfile(user.id));

const [user, config, profile] = await Promise.all([
  userPromise,
  fetchConfig(),
  profilePromise,
]);
链式处理依赖操作,并行处理独立操作。
typescript
// 不良实践:profile不必要地等待config加载
const [user, config] = await Promise.all([fetchUser(), fetchConfig()]);
const profile = await fetchProfile(user.id);

// 最佳实践:user加载完成后立即开始加载profile
const userPromise = fetchUser();
const profilePromise = userPromise.then((user) => fetchProfile(user.id));

const [user, config, profile] = await Promise.all([
  userPromise,
  fetchConfig(),
  profilePromise,
]);

api-routes (CRITICAL) — @rules/api-routes.md

API路由(严重)——@rules/api-routes.md

Start promises early, await late in loaders.
typescript
// Bad: sequential execution
export async function loader() {
  let session = await auth();
  let config = await fetchConfig();
  return { session, config };
}

// Good: parallel execution
export async function loader() {
  let sessionPromise = auth();
  let configPromise = fetchConfig();
  const [session, config] = await Promise.all([sessionPromise, configPromise]);
  return { session, config };
}
尽早创建Promise,在加载器中延迟await。
typescript
// 不良实践:顺序执行
export async function loader() {
  let session = await auth();
  let config = await fetchConfig();
  return { session, config };
}

// 最佳实践:并行执行
export async function loader() {
  let sessionPromise = auth();
  let configPromise = fetchConfig();
  const [session, config] = await Promise.all([sessionPromise, configPromise]);
  return { session, config };
}

suspense-boundaries (HIGH) — @rules/suspense-boundaries.md

Suspense边界(高)——@rules/suspense-boundaries.md

Use Suspense to show UI immediately while data loads.
tsx
// Bad: entire page blocked by data
async function Page() {
  let data = await fetchData();
  return (
    <Layout>
      <Content data={data} />
    </Layout>
  );
}

// Good: layout shows immediately, content streams in
function Page() {
  return (
    <Layout>
      <Suspense fallback={<Skeleton />}>
        <Content />
      </Suspense>
    </Layout>
  );
}
使用Suspense在数据加载时立即显示UI。
tsx
// 不良实践:整个页面被数据加载阻塞
async function Page() {
  let data = await fetchData();
  return (
    <Layout>
      <Content data={data} />
    </Layout>
  );
}

// 最佳实践:布局立即显示,内容流式加载
function Page() {
  return (
    <Layout>
      <Suspense fallback={<Skeleton />}>
        <Content />
      </Suspense>
    </Layout>
  );
}