Skip to content

⏳ Async Programming ​

Writing correct and performant asynchronous code.

Promises and async/await ​

typescript
// Sequential β€” each waits for the previous
const user = await getUser(id)
const orders = await getOrders(user.id)
const payments = await getPayments(orders)

// Parallel β€” independent operations at the same time
const [user, products, settings] = await Promise.all([
  getUser(id),
  getProducts(),
  getSettings(),
])

Promise combinators ​

MethodBehavior
Promise.allResolves when ALL resolve; rejects on first rejection
Promise.allSettledWaits for all; returns status of each
Promise.raceResolves/rejects with the first to settle
Promise.anyResolves with first success; rejects if all fail

Error handling ​

typescript
// Always handle rejections
try {
  const data = await fetchData()
} catch (error) {
  // Handle specific errors
  if (error instanceof NetworkError) {
    // retry logic
  }
  throw error // re-throw if can't handle
}

Common patterns ​

Retry with backoff ​

typescript
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn()
    } catch (error) {
      if (i === maxRetries - 1) throw error
      await sleep(Math.pow(2, i) * 1000) // exponential backoff
    }
  }
  throw new Error('Unreachable')
}

Concurrency limit ​

typescript
// Process 10 items at a time, not all at once
import pLimit from 'p-limit'
const limit = pLimit(10)
const results = await Promise.all(
  items.map(item => limit(() => processItem(item)))
)

Anti-patterns ​

  • await inside a loop when operations are independent
  • Missing error handling on promises (unhandled rejection)
  • Mixing callbacks and promises
  • Creating a promise in a function that's already async
  • Not using Promise.all for independent parallel work
  • Fire-and-forget without error handling

Pergame Knowledge Base