Skip to content

perf: cut microtask ticks in ResultAsync chains - #689

Open
hood wants to merge 1 commit into
supermacro:masterfrom
hood:perf/async-ticks
Open

hood wants to merge 1 commit into
supermacro:masterfrom
hood:perf/async-ticks

Conversation

@hood

@hood hood commented Nov 5, 2026

Copy link
Copy Markdown

Summary

Removes the async callbacks from ResultAsync.map, mapErr and orElse, and reuses the existing Result on skipped branches (also in andThen). Sync callbacks no longer pay for an extra promise and tick; async callbacks are chained only when f returns a thenable.

Closes #688

Results

Node 26, median of 5 runs, esbuild CJS bundle of src/.

Benchmark Before After Gain
11-step Ok chain, microtask ticks 32 12 2.7x
6-step Err chain, microtask ticks 17 7 2.4x
11-step Ok chain, time 1.67µs 0.77µs 2.2x
flowchart LR
  A[then cb] -->|before| B[async fn promise] --> C[await f] --> D[resolve outer]
  A -->|after| E[f sync] --> F[return Ok]
Loading

Notes

  • Sync throws inside f still reject the chain (thrown inside .then), same as before.
  • orElse now unwraps a returned ResultAsync via _promise, like andThen already does.
  • Skipped branches return the same Ok/Err instance instead of a copy.
  • All 117 tests, tsc, test types and lint pass.

@changeset-bot

changeset-bot Bot commented Nov 5, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 711d72b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
neverthrow Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ResultAsync steps cost ~3 microtask ticks instead of 1

1 participant