# Async operations return Promises

- **Pattern:** `ab-002356` (`sdk-package-quality.api-surface.async-promises`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002356
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002356)

## Why it matters

Callback-based async APIs are incompatible with `async/await`, require consumers to wrap calls in `new Promise()` to compose them, and produce inverted error-handling patterns compared to modern JavaScript. ISO 25010 interoperability degrades when your API cannot be composed with `Promise.all`, `Promise.race`, or `async` middleware chains. Callback-only APIs also make it harder to surface errors correctly — thrown errors inside callbacks are swallowed by the event loop if the callback doesn't explicitly handle them.

## Severity rationale

Medium because callback-only APIs block `async/await` usage and complicate error propagation, but do not cause immediate failures — they require consumers to add boilerplate wrapping.

## Remediation

Convert callback-based methods to `async` functions returning typed Promises.

```ts
// Before — callback pattern:
export function fetchData(
  url: string,
  callback: (err: Error | null, data?: ResponseData) => void
) { /* ... */ }

// After — Promise pattern:
export async function fetchData(url: string): Promise<ResponseData> {
  const response = await fetch(url)
  if (!response.ok) throw new ApiError('Request failed', response.status)
  return response.json() as Promise<ResponseData>
}
```

If you need to maintain backward compatibility during a migration, add the Promise API alongside the callback API and deprecate the callback variant with a JSDoc `@deprecated` tag.

## Detection

- **ID:** `async-promises`
- **Severity:** `medium`
- **What to look for:** List all async operations in the public API. For each, examine exported functions and methods that perform asynchronous operations (network requests, file I/O, database queries). Check whether they:
  1. Return `Promise<T>` or use `async/await`
  2. Use callbacks instead of Promises
  3. Return `void` but perform async work (fire-and-forget)
  4. Have consistent async patterns (all async functions return Promises, not a mix of callbacks and Promises)
- **Pass criteria:** All asynchronous operations in the public API return Promises (either explicitly or via `async` functions). The package does not require consumers to pass callback functions for async results — 100% of async operations must return Promises (no callback-only APIs). Report: "X async operations found, all Y return Promises."
- **Fail criteria:** The public API uses callbacks for asynchronous operations (e.g., `client.fetch(url, callback)`), or async methods return `void` and report results through event emitters or side channels without also providing a Promise-based API.
- **Skip (N/A) when:** The package is entirely synchronous — no async operations, no I/O, no network calls. Pure computation libraries, parsers, and formatters typically fall into this category. Also skip for Go (uses channels/goroutines) and Rust (uses different async patterns).
- **Detail on fail:** `"The createClient().fetch() method takes a callback parameter instead of returning a Promise. Consumers cannot use async/await: client.fetch(url, (err, data) => { ... }). This is a Node.js callback pattern from before Promises were standard."`
- **Remediation:** Promises are the standard async pattern in modern JavaScript. They compose with `async/await`, error handling is consistent, and they work with every modern framework.

  ```ts
  // Before — callback pattern:
  export function fetchData(
    url: string,
    callback: (err: Error | null, data?: any) => void
  ) {
    // ...
  }

  // After — Promise pattern:
  export async function fetchData(url: string): Promise<ResponseData> {
    const response = await fetch(url)
    if (!response.ok) throw new ApiError(response.status)
    return response.json()
  }
  ```

## External references

- iso-25010 compatibility.interoperability
- iso-25010 maintainability.modifiability

Taxons: code-quality, user-experience

HTML version: https://auditbuffet.com/patterns/ab-002356
