Skip to content
Development
Agent

react-async-patterns

<!-- Loaded by performance-optimization-engineer when task involves async data fetching, waterfalls, or parallelization -->

From plugin
vexjoy-agent
449198 skills198 agents12 commands83 hooks

Claude Code

$ npx -y skills add notque/vexjoy-agent --agent claude-code

Agent definition

react-async-patterns.md

React Async Patterns Reference

<!-- Loaded by performance-optimization-engineer when task involves async data fetching, waterfalls, or parallelization -->

Promise.all for Independent Operations

**Impact:** CRITICAL — 2-10x improvement

Independent async operations complete in the time of the slowest, not the sum of all. `Promise.all` enables parallel fetching for any operations with no interdependencies.

**Instead of:**

const user = await fetchUser()
const posts = await fetchPosts()
const comments = await fetchComments()
// Total time: fetchUser + fetchPosts + fetchComments

**Use:**

const [user, posts, comments] = await Promise.all([
  fetchUser(),
  fetchPosts(),
  fetchComments()
])
// Total time: max(fetchUser, fetchPosts, fetchComments)

---

Cheap Condition Before Await

**Impact:** HIGH — avoids unnecessary async work when a synchronous guard already fails

When a branch uses `await` for a flag or remote value and also requires a cheap synchronous condition (local props, already-loaded state), evaluate the cheap condition first. Otherwise you pay for the async call even when the compound condition can never be true.

**Instead of:**

const someFlag = await getFlag()

if (someFlag && someCondition) {
  // ...
}

**Use:**

if (someCondition) {
  const someFlag = await getFlag()
  if (someFlag) {
    // ...
  }
}

This matters when `getFlag` hits the network, a feature-flag service, or a cache: skipping it when `someCondition` is false removes that cost on the cold path.

Keep the original order if `someCondition` is expensive, depends on the flag, or side effects must run in fixed order.

---

Defer Await to Maximize Parallelism

**Impact:** HIGH — avoids blocking unused code paths

Move `await` into the branches where the result is actually used. Starting a fetch does not require awaiting it immediately — and returning early before an await means the fetch never happens at all.

**Instead of:**

async function handleRequest(userId: string, skipProcessing: boolean) {
  const userData = await fetchUserData(userId)

  if (skipProcessing) {
    return { skipped: true } // still waited for userData
  }

  return processUserData(userData)
}

**Use:**

async function handleRequest(userId: string, skipProcessing: boolean) {
  if (skipProcessing) {
    return { skipped: true } // no fetch at all
  }

  const userData = await fetchUserData(userId)
  return processUserData(userData)
}

Another example — ordering awaits by dependency rather than by declaration:

// fetch only what each step actually needs, in the order needed
async function updateResource(resourceId: string, userId: string) {
  const resource = await getResource(resourceId)
  if (!resource) return { error: 'Not found' }

  const permissions = await fetchPermissions(userId)
  if (!permissions.canEdit) return { error: 'Forbidden' }

  return updateResourceData(resource, permissions)
}

This optimization is especially valuable when the skipped branch is frequently taken or when the deferred operation is expensive.

---

Dependency-Based Parallelization

**Impact:** CRITICAL — 2-10x improvement

When operations have partial dependencies (B needs A, but C is independent of both), naive `Promise.all` groups them incorrectly and serializes what could be parallel. Starting each operation as early as possible — by chaining off the promise rather than the resolved value — maximizes concurrency.

**Instead of:**

const [user, config] = await Promise.all([fetchUser(), fetchConfig()])
const profile = await fetchProfile(user.id) // profile forced to wait for config

**Use:**

const userPromise = fetchUser()
const profilePromise = userPromise.then(user => fetchProfile(user.id))

const [user, config, profile] = await Promise.all([
  userPromise,
  fetchConfig(), // runs in parallel with user and profile chain
  profilePromise
])

For complex dependency graphs, the `better-all` library provides a declarative API that automatically starts each task at the earliest possible moment:

import { all } from 'better-all'

const { user, config, profile } = await all({
  async user() { return fetchUser() },
  async config() { return fetchConfig() },
  async profile() {
    return fetchProfile((await this.$.user).id)
  }
})

Reference: [better-all](https://github.com/shuding/better-all)

---

Suspense Boundaries for Streaming

**Impact:** HIGH — faster initial paint

Instead of awaiting all data before returning JSX, use Suspense boundaries to show wrapper UI immediately while data streams in. Only the component that needs the data blocks — the rest of the page renders without waiting.

**Instead of:**

async function Page() {
  const data = await fetchData() // blocks entire page

  return (
    <div>
      <Sidebar />
      <Header />
      <DataDisplay data={data} />
      <Footer />
    </div>
  )
}

**Use:**

function Page() {
  return (
    <div>
      <Sidebar />
      <Header />
      <Suspense fallback={<Skeleton />}>
        <DataDisplay />
      </Suspense>
      <Footer />
    </div>
  )
}

async function DataDisplay() {
  const data = await fetchData() // only blocks this component
  return <div>{data.content}</div>
}

When multiple components share the same data, pass the promise down rather than fetching separately — one network request, shared across both:

function Page() {
  const dataPromise = fetchData() // start fetch, don't await

  return (
    <Suspense fallback={<Skeleton />}>
      <DataDisplay dataPromise={dataPromise} />
      <DataSummary dataPromise={dataPromise} />
    </Suspense>
  )
}

function DataDisplay({ dataPromise }: { dataPromise: Promise<Data> }) {
  const data = use(dataPromise)
  return <div>{data.content}</div>
}

When not to apply: SEO-critical above-fold content, data needed for layout decisio

Read more
@notque
Ships withvexjoy-agent

Essays and writing behind this toolkit live at vexjoy.com. VexJoy Agent connects plain-English requests to specialist agents, skills, and workflows. /do selects the knowledge and tools needed for your task.

44964 skills198 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
449
Star history of notque/vexjoy-agent on GitHub, a chart by star-history.com

Other agents on vexjoy-agent.

modules

modules

Agent

**Scope**: Module selection patterns, builtin vs command/shell decisions, collection modules, and version-specific module changes…

@notque@notqueInstall Agent
testing

testing

Agent

**Scope**: Molecule test scenarios, ansible-lint rules, idempotency validation, and check-mode patterns **Version range**:…

@notque@notqueInstall Agent
communication-patterns

communication-patterns

Agent

**Scope**: Failure modes in agent output style — over-reporting, self-congratulation, verbose narration, and hedging. Covers what…

@notque@notqueInstall Agent

More agents from other plugins.

a11y-architect
Auto-invoked

a11y-architect

Agent

Accessibility Architect specializing in WCAG 2.2 compliance for Web and Native platforms. Use PROACTIVELY when designing UI…

ecc13d293k
@affaan-m@affaan-mInstall Agent
analyze-pass-impact

analyze-pass-impact

Agent

Analyzes how a specific topic affects a group of compiler passes. Used by the /plan-update skill to parallelize research across…

react2d252k
@facebook@facebookInstall Agent
orchestrator

orchestrator

Agent

- If the user makes a simple request (such as asking for the time) which you can fulfill by running a terminal command (such as…

codex2d135k
@openai@openaiInstall Agent
cavecrew-builder

cavecrew-builder

Agent

Surgical 1-2 file edit. Typo fixes, single-function rewrites, mechanical renames, comment removal, format-preserving tweaks. Hard…

caveman3d119k
@juliusbrussee@juliusbrusseeInstall Agent

Questions about react-async-patterns.

Which coding agents can use react-async-patterns?
react-async-patterns installs in Claude Code and Cursor: each loads subagents from .claude/agents, so copy the file there. Flowy's auto-invocation runs in Claude Code only.